From 1f1aaa24aebac2555d7106e8e8ab1ed2fd153ca7 Mon Sep 17 00:00:00 2001 From: "Jenkins, Kenneth Alexander" Date: Mon, 6 Apr 2026 14:50:34 -0400 Subject: [PATCH] second round of translation fixes Signed-off-by: Jenkins, Kenneth Alexander --- .coverage | Bin 0 -> 53248 bytes docs/tech-specs/__TEMPLATE.ar.md | 127 +++ docs/tech-specs/__TEMPLATE.es.md | 127 +++ docs/tech-specs/__TEMPLATE.he.md | 127 +++ docs/tech-specs/__TEMPLATE.hi.md | 127 +++ docs/tech-specs/__TEMPLATE.pt.md | 127 +++ docs/tech-specs/__TEMPLATE.ru.md | 127 +++ docs/tech-specs/__TEMPLATE.sw.md | 127 +++ docs/tech-specs/__TEMPLATE.tr.md | 127 +++ docs/tech-specs/__TEMPLATE.zh-cn.md | 127 +++ docs/tech-specs/agent-explainability.ar.md | 272 ++++++ docs/tech-specs/agent-explainability.es.md | 272 ++++++ docs/tech-specs/agent-explainability.he.md | 272 ++++++ docs/tech-specs/agent-explainability.hi.md | 272 ++++++ docs/tech-specs/agent-explainability.pt.md | 272 ++++++ docs/tech-specs/agent-explainability.ru.md | 272 ++++++ docs/tech-specs/agent-explainability.sw.md | 272 ++++++ docs/tech-specs/agent-explainability.tr.md | 272 ++++++ docs/tech-specs/agent-explainability.zh-cn.md | 272 ++++++ docs/tech-specs/architecture-principles.ar.md | 106 +++ docs/tech-specs/architecture-principles.es.md | 106 +++ docs/tech-specs/architecture-principles.he.md | 106 +++ docs/tech-specs/architecture-principles.hi.md | 106 +++ docs/tech-specs/architecture-principles.pt.md | 106 +++ docs/tech-specs/architecture-principles.ru.md | 106 +++ docs/tech-specs/architecture-principles.sw.md | 106 +++ docs/tech-specs/architecture-principles.tr.md | 106 +++ .../architecture-principles.zh-cn.md | 106 +++ docs/tech-specs/cassandra-consolidation.ar.md | 331 +++++++ docs/tech-specs/cassandra-consolidation.he.md | 331 +++++++ docs/tech-specs/cassandra-consolidation.hi.md | 331 +++++++ docs/tech-specs/cassandra-consolidation.pt.md | 331 +++++++ docs/tech-specs/cassandra-consolidation.ru.md | 331 +++++++ docs/tech-specs/cassandra-consolidation.sw.md | 331 +++++++ docs/tech-specs/cassandra-consolidation.tr.md | 331 +++++++ .../cassandra-consolidation.zh-cn.md | 331 +++++++ .../cassandra-performance-refactor.ar.md | 679 ++++++++++++++ .../cassandra-performance-refactor.es.md | 679 ++++++++++++++ .../cassandra-performance-refactor.he.md | 679 ++++++++++++++ .../cassandra-performance-refactor.hi.md | 679 ++++++++++++++ .../cassandra-performance-refactor.pt.md | 679 ++++++++++++++ .../cassandra-performance-refactor.ru.md | 679 ++++++++++++++ .../cassandra-performance-refactor.sw.md | 679 ++++++++++++++ .../cassandra-performance-refactor.tr.md | 679 ++++++++++++++ .../cassandra-performance-refactor.zh-cn.md | 679 ++++++++++++++ docs/tech-specs/collection-management.ar.md | 403 ++++++++ docs/tech-specs/collection-management.es.md | 403 ++++++++ docs/tech-specs/collection-management.he.md | 403 ++++++++ docs/tech-specs/collection-management.hi.md | 403 ++++++++ docs/tech-specs/collection-management.pt.md | 403 ++++++++ docs/tech-specs/collection-management.ru.md | 403 ++++++++ docs/tech-specs/collection-management.sw.md | 403 ++++++++ docs/tech-specs/collection-management.tr.md | 403 ++++++++ .../tech-specs/collection-management.zh-cn.md | 403 ++++++++ .../document-embeddings-chunk-id.ar.md | 136 +++ .../document-embeddings-chunk-id.es.md | 136 +++ .../document-embeddings-chunk-id.he.md | 136 +++ .../document-embeddings-chunk-id.hi.md | 136 +++ .../document-embeddings-chunk-id.pt.md | 136 +++ .../document-embeddings-chunk-id.ru.md | 136 +++ .../document-embeddings-chunk-id.sw.md | 136 +++ .../document-embeddings-chunk-id.tr.md | 136 +++ .../document-embeddings-chunk-id.zh-cn.md | 136 +++ .../embeddings-batch-processing.ar.md | 667 +++++++++++++ .../embeddings-batch-processing.es.md | 667 +++++++++++++ .../embeddings-batch-processing.he.md | 667 +++++++++++++ .../embeddings-batch-processing.hi.md | 667 +++++++++++++ .../embeddings-batch-processing.pt.md | 667 +++++++++++++ .../embeddings-batch-processing.ru.md | 667 +++++++++++++ .../embeddings-batch-processing.sw.md | 667 +++++++++++++ .../embeddings-batch-processing.tr.md | 667 +++++++++++++ .../embeddings-batch-processing.zh-cn.md | 667 +++++++++++++ docs/tech-specs/entity-centric-graph.ar.md | 261 ++++++ docs/tech-specs/entity-centric-graph.es.md | 261 ++++++ docs/tech-specs/entity-centric-graph.he.md | 261 ++++++ docs/tech-specs/entity-centric-graph.hi.md | 261 ++++++ docs/tech-specs/entity-centric-graph.pt.md | 261 ++++++ docs/tech-specs/entity-centric-graph.ru.md | 261 ++++++ docs/tech-specs/entity-centric-graph.sw.md | 261 ++++++ docs/tech-specs/entity-centric-graph.tr.md | 261 ++++++ docs/tech-specs/entity-centric-graph.zh-cn.md | 261 ++++++ docs/tech-specs/explainability-cli.he.md | 220 +++++ docs/tech-specs/explainability-cli.hi.md | 220 +++++ docs/tech-specs/explainability-cli.pt.md | 220 +++++ docs/tech-specs/explainability-cli.ru.md | 220 +++++ docs/tech-specs/explainability-cli.sw.md | 220 +++++ docs/tech-specs/explainability-cli.tr.md | 220 +++++ docs/tech-specs/extraction-flows.ar.md | 347 +++++++ docs/tech-specs/extraction-flows.es.md | 347 +++++++ docs/tech-specs/extraction-flows.he.md | 347 +++++++ docs/tech-specs/extraction-flows.hi.md | 347 +++++++ docs/tech-specs/extraction-flows.pt.md | 347 +++++++ docs/tech-specs/extraction-flows.ru.md | 347 +++++++ docs/tech-specs/extraction-flows.sw.md | 347 +++++++ docs/tech-specs/extraction-flows.tr.md | 347 +++++++ docs/tech-specs/extraction-flows.zh-cn.md | 347 +++++++ .../extraction-provenance-subgraph.es.md | 205 ++++ docs/tech-specs/graph-contexts.ar.md | 336 +++++++ docs/tech-specs/graph-contexts.es.md | 386 ++++++++ docs/tech-specs/graph-contexts.he.md | 316 +++++++ docs/tech-specs/graph-contexts.hi.md | 368 ++++++++ docs/tech-specs/graph-contexts.ru.md | 407 ++++++++ docs/tech-specs/graph-contexts.sw.md | 351 +++++++ docs/tech-specs/graph-contexts.zh-cn.md | 417 +++++++++ .../graphrag-performance-optimization.ar.md | 270 ++++++ .../graphrag-performance-optimization.es.md | 301 ++++++ .../graphrag-performance-optimization.he.md | 101 ++ .../graphrag-performance-optimization.hi.md | 144 +++ .../graphrag-performance-optimization.ru.md | 124 +++ .../graphrag-performance-optimization.sw.md | 240 +++++ ...graphrag-performance-optimization.zh-cn.md | 364 ++++++++ docs/tech-specs/jsonl-prompt-output.ar.md | 74 ++ docs/tech-specs/jsonl-prompt-output.es.md | 75 ++ docs/tech-specs/jsonl-prompt-output.he.md | 51 + docs/tech-specs/jsonl-prompt-output.hi.md | 88 ++ docs/tech-specs/jsonl-prompt-output.sw.md | 618 ++++++++++++ docs/tech-specs/more-config-cli.hi.md | 195 ++++ docs/tech-specs/more-config-cli.sw.md | 197 ++++ .../neo4j-user-collection-isolation.ar.md | 190 ++++ .../neo4j-user-collection-isolation.hi.md | 134 +++ .../neo4j-user-collection-isolation.sw.md | 184 ++++ docs/tech-specs/ontology.ar.md | 171 ++++ docs/tech-specs/ontology.es.md | 269 ++++++ docs/tech-specs/ontology.hi.md | 180 ++++ docs/tech-specs/ontology.sw.md | 147 +++ docs/tech-specs/structured-data-schemas.hi.md | 139 +++ docs/tech-specs/universal-decoder.ar.md | 411 ++++++++ docs/tech-specs/universal-decoder.he.md | 196 ++++ docs/tech-specs/universal-decoder.sw.md | 220 +++++ docs/tech-specs/universal-decoder.zh-cn.md | 289 ++++++ generate_i18n_packs.py | 233 +++++ tests/conftest.py | 14 +- tests/unit/test_base/test_i18n.py | 40 + tests/unit/test_gateway/test_endpoint_i18n.py | 75 ++ translate_docs.py | 880 ++++++++++++++++-- trustgraph-base/pyproject.toml | 3 + trustgraph-base/trustgraph/i18n/__init__.py | 153 +++ .../trustgraph/i18n/packs/__init__.py | 1 + trustgraph-base/trustgraph/i18n/packs/ar.json | 54 ++ trustgraph-base/trustgraph/i18n/packs/en.json | 54 ++ trustgraph-base/trustgraph/i18n/packs/es.json | 54 ++ trustgraph-base/trustgraph/i18n/packs/he.json | 54 ++ trustgraph-base/trustgraph/i18n/packs/hi.json | 54 ++ trustgraph-base/trustgraph/i18n/packs/pt.json | 54 ++ trustgraph-base/trustgraph/i18n/packs/ru.json | 54 ++ trustgraph-base/trustgraph/i18n/packs/sw.json | 54 ++ trustgraph-base/trustgraph/i18n/packs/tr.json | 54 ++ .../trustgraph/i18n/packs/zh-cn.json | 54 ++ .../trustgraph/cli/verify_system_status.py | 169 ++-- .../trustgraph/gateway/endpoint/i18n.py | 45 + .../trustgraph/gateway/endpoint/manager.py | 5 + trustgraph/trustgraph/trustgraph_version.py | 1 + 152 files changed, 41130 insertions(+), 137 deletions(-) create mode 100644 .coverage create mode 100644 docs/tech-specs/__TEMPLATE.ar.md create mode 100644 docs/tech-specs/__TEMPLATE.es.md create mode 100644 docs/tech-specs/__TEMPLATE.he.md create mode 100644 docs/tech-specs/__TEMPLATE.hi.md create mode 100644 docs/tech-specs/__TEMPLATE.pt.md create mode 100644 docs/tech-specs/__TEMPLATE.ru.md create mode 100644 docs/tech-specs/__TEMPLATE.sw.md create mode 100644 docs/tech-specs/__TEMPLATE.tr.md create mode 100644 docs/tech-specs/__TEMPLATE.zh-cn.md create mode 100644 docs/tech-specs/agent-explainability.ar.md create mode 100644 docs/tech-specs/agent-explainability.es.md create mode 100644 docs/tech-specs/agent-explainability.he.md create mode 100644 docs/tech-specs/agent-explainability.hi.md create mode 100644 docs/tech-specs/agent-explainability.pt.md create mode 100644 docs/tech-specs/agent-explainability.ru.md create mode 100644 docs/tech-specs/agent-explainability.sw.md create mode 100644 docs/tech-specs/agent-explainability.tr.md create mode 100644 docs/tech-specs/agent-explainability.zh-cn.md create mode 100644 docs/tech-specs/architecture-principles.ar.md create mode 100644 docs/tech-specs/architecture-principles.es.md create mode 100644 docs/tech-specs/architecture-principles.he.md create mode 100644 docs/tech-specs/architecture-principles.hi.md create mode 100644 docs/tech-specs/architecture-principles.pt.md create mode 100644 docs/tech-specs/architecture-principles.ru.md create mode 100644 docs/tech-specs/architecture-principles.sw.md create mode 100644 docs/tech-specs/architecture-principles.tr.md create mode 100644 docs/tech-specs/architecture-principles.zh-cn.md create mode 100644 docs/tech-specs/cassandra-consolidation.ar.md create mode 100644 docs/tech-specs/cassandra-consolidation.he.md create mode 100644 docs/tech-specs/cassandra-consolidation.hi.md create mode 100644 docs/tech-specs/cassandra-consolidation.pt.md create mode 100644 docs/tech-specs/cassandra-consolidation.ru.md create mode 100644 docs/tech-specs/cassandra-consolidation.sw.md create mode 100644 docs/tech-specs/cassandra-consolidation.tr.md create mode 100644 docs/tech-specs/cassandra-consolidation.zh-cn.md create mode 100644 docs/tech-specs/cassandra-performance-refactor.ar.md create mode 100644 docs/tech-specs/cassandra-performance-refactor.es.md create mode 100644 docs/tech-specs/cassandra-performance-refactor.he.md create mode 100644 docs/tech-specs/cassandra-performance-refactor.hi.md create mode 100644 docs/tech-specs/cassandra-performance-refactor.pt.md create mode 100644 docs/tech-specs/cassandra-performance-refactor.ru.md create mode 100644 docs/tech-specs/cassandra-performance-refactor.sw.md create mode 100644 docs/tech-specs/cassandra-performance-refactor.tr.md create mode 100644 docs/tech-specs/cassandra-performance-refactor.zh-cn.md create mode 100644 docs/tech-specs/collection-management.ar.md create mode 100644 docs/tech-specs/collection-management.es.md create mode 100644 docs/tech-specs/collection-management.he.md create mode 100644 docs/tech-specs/collection-management.hi.md create mode 100644 docs/tech-specs/collection-management.pt.md create mode 100644 docs/tech-specs/collection-management.ru.md create mode 100644 docs/tech-specs/collection-management.sw.md create mode 100644 docs/tech-specs/collection-management.tr.md create mode 100644 docs/tech-specs/collection-management.zh-cn.md create mode 100644 docs/tech-specs/document-embeddings-chunk-id.ar.md create mode 100644 docs/tech-specs/document-embeddings-chunk-id.es.md create mode 100644 docs/tech-specs/document-embeddings-chunk-id.he.md create mode 100644 docs/tech-specs/document-embeddings-chunk-id.hi.md create mode 100644 docs/tech-specs/document-embeddings-chunk-id.pt.md create mode 100644 docs/tech-specs/document-embeddings-chunk-id.ru.md create mode 100644 docs/tech-specs/document-embeddings-chunk-id.sw.md create mode 100644 docs/tech-specs/document-embeddings-chunk-id.tr.md create mode 100644 docs/tech-specs/document-embeddings-chunk-id.zh-cn.md create mode 100644 docs/tech-specs/embeddings-batch-processing.ar.md create mode 100644 docs/tech-specs/embeddings-batch-processing.es.md create mode 100644 docs/tech-specs/embeddings-batch-processing.he.md create mode 100644 docs/tech-specs/embeddings-batch-processing.hi.md create mode 100644 docs/tech-specs/embeddings-batch-processing.pt.md create mode 100644 docs/tech-specs/embeddings-batch-processing.ru.md create mode 100644 docs/tech-specs/embeddings-batch-processing.sw.md create mode 100644 docs/tech-specs/embeddings-batch-processing.tr.md create mode 100644 docs/tech-specs/embeddings-batch-processing.zh-cn.md create mode 100644 docs/tech-specs/entity-centric-graph.ar.md create mode 100644 docs/tech-specs/entity-centric-graph.es.md create mode 100644 docs/tech-specs/entity-centric-graph.he.md create mode 100644 docs/tech-specs/entity-centric-graph.hi.md create mode 100644 docs/tech-specs/entity-centric-graph.pt.md create mode 100644 docs/tech-specs/entity-centric-graph.ru.md create mode 100644 docs/tech-specs/entity-centric-graph.sw.md create mode 100644 docs/tech-specs/entity-centric-graph.tr.md create mode 100644 docs/tech-specs/entity-centric-graph.zh-cn.md create mode 100644 docs/tech-specs/explainability-cli.he.md create mode 100644 docs/tech-specs/explainability-cli.hi.md create mode 100644 docs/tech-specs/explainability-cli.pt.md create mode 100644 docs/tech-specs/explainability-cli.ru.md create mode 100644 docs/tech-specs/explainability-cli.sw.md create mode 100644 docs/tech-specs/explainability-cli.tr.md create mode 100644 docs/tech-specs/extraction-flows.ar.md create mode 100644 docs/tech-specs/extraction-flows.es.md create mode 100644 docs/tech-specs/extraction-flows.he.md create mode 100644 docs/tech-specs/extraction-flows.hi.md create mode 100644 docs/tech-specs/extraction-flows.pt.md create mode 100644 docs/tech-specs/extraction-flows.ru.md create mode 100644 docs/tech-specs/extraction-flows.sw.md create mode 100644 docs/tech-specs/extraction-flows.tr.md create mode 100644 docs/tech-specs/extraction-flows.zh-cn.md create mode 100644 docs/tech-specs/extraction-provenance-subgraph.es.md create mode 100644 docs/tech-specs/graph-contexts.ar.md create mode 100644 docs/tech-specs/graph-contexts.es.md create mode 100644 docs/tech-specs/graph-contexts.he.md create mode 100644 docs/tech-specs/graph-contexts.hi.md create mode 100644 docs/tech-specs/graph-contexts.ru.md create mode 100644 docs/tech-specs/graph-contexts.sw.md create mode 100644 docs/tech-specs/graph-contexts.zh-cn.md create mode 100644 docs/tech-specs/graphrag-performance-optimization.ar.md create mode 100644 docs/tech-specs/graphrag-performance-optimization.es.md create mode 100644 docs/tech-specs/graphrag-performance-optimization.he.md create mode 100644 docs/tech-specs/graphrag-performance-optimization.hi.md create mode 100644 docs/tech-specs/graphrag-performance-optimization.ru.md create mode 100644 docs/tech-specs/graphrag-performance-optimization.sw.md create mode 100644 docs/tech-specs/graphrag-performance-optimization.zh-cn.md create mode 100644 docs/tech-specs/jsonl-prompt-output.ar.md create mode 100644 docs/tech-specs/jsonl-prompt-output.es.md create mode 100644 docs/tech-specs/jsonl-prompt-output.he.md create mode 100644 docs/tech-specs/jsonl-prompt-output.hi.md create mode 100644 docs/tech-specs/jsonl-prompt-output.sw.md create mode 100644 docs/tech-specs/more-config-cli.hi.md create mode 100644 docs/tech-specs/more-config-cli.sw.md create mode 100644 docs/tech-specs/neo4j-user-collection-isolation.ar.md create mode 100644 docs/tech-specs/neo4j-user-collection-isolation.hi.md create mode 100644 docs/tech-specs/neo4j-user-collection-isolation.sw.md create mode 100644 docs/tech-specs/ontology.ar.md create mode 100644 docs/tech-specs/ontology.es.md create mode 100644 docs/tech-specs/ontology.hi.md create mode 100644 docs/tech-specs/ontology.sw.md create mode 100644 docs/tech-specs/structured-data-schemas.hi.md create mode 100644 docs/tech-specs/universal-decoder.ar.md create mode 100644 docs/tech-specs/universal-decoder.he.md create mode 100644 docs/tech-specs/universal-decoder.sw.md create mode 100644 docs/tech-specs/universal-decoder.zh-cn.md create mode 100644 generate_i18n_packs.py create mode 100644 tests/unit/test_base/test_i18n.py create mode 100644 tests/unit/test_gateway/test_endpoint_i18n.py mode change 100644 => 100755 translate_docs.py create mode 100644 trustgraph-base/trustgraph/i18n/__init__.py create mode 100644 trustgraph-base/trustgraph/i18n/packs/__init__.py create mode 100644 trustgraph-base/trustgraph/i18n/packs/ar.json create mode 100644 trustgraph-base/trustgraph/i18n/packs/en.json create mode 100644 trustgraph-base/trustgraph/i18n/packs/es.json create mode 100644 trustgraph-base/trustgraph/i18n/packs/he.json create mode 100644 trustgraph-base/trustgraph/i18n/packs/hi.json create mode 100644 trustgraph-base/trustgraph/i18n/packs/pt.json create mode 100644 trustgraph-base/trustgraph/i18n/packs/ru.json create mode 100644 trustgraph-base/trustgraph/i18n/packs/sw.json create mode 100644 trustgraph-base/trustgraph/i18n/packs/tr.json create mode 100644 trustgraph-base/trustgraph/i18n/packs/zh-cn.json create mode 100644 trustgraph-flow/trustgraph/gateway/endpoint/i18n.py create mode 100644 trustgraph/trustgraph/trustgraph_version.py diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..7ec3fd07cd1ebbef8a53d57204a39adf454cfd50 GIT binary patch literal 53248 zcmeI)%WoS+90%~-y7k76BL_v16>`X2kYm+xWmSmR0Rlv#q7oDW;)FZ4$M%AE*V#uN z2ZUTIl`D7tIR1i495`{|_nX=E+DTmXR%!XJVrL&Sv-A7R%kH-Q_Q_*6R$>%{o{Ysq zYumDI>k}a?%i5sV7QM2~p`E+g0sXd@_SfxhSe-xq+NytV)yh9u^&hw1t{>ILwZAw2 zti50PZqs$zl@49N1_1~_00M;(m_MmGjlDhl*)Or|PgNYsfeOw0)@R?G9G{+u)8kJc zp9phK999KwM@QmVgu#WFsZfmEsS>U~bO$na{jrEADodS2YRGFAougHY6Lxfd-s`zT z$`z|I6)_84Pli|GXLZ%q3DUd8>M}Mbs1W6jeNG_`)9ft~s*wtnKTwgW#i2WFRa?LP zT6G#bJN65uW0K*3el}O4p%Zy1k499`AP9$C`+g|>!9+!EAr}!20;=a_Y@!VV??D`h zsq5=7{m6~oz!&OL4U$+5Zw;``XxT=1%h6C-PdT8cCTDuDC7nF;EjiQVY331C&JQxy zJR{$lGV40~iPtCcpAv7zjYB!ijpJZl&UJa?APx4l+vb+G%;Q~Y&WxN})Z|Kh_bgG1 z#&3%}XIqEi2W`PYP!D)#v)uS#$F`_fs>|qXN*|qiGKm9y+@r?tb?L44{H+bAad2S2 zIMW@4d3t>}jutzWl}@uby{7B%_4WORN6Bg@;ZZc5ieRLN4CfZ6ai}*hkC_Jc&J1i!yq_Up&YADdeuw|Z@ME< z*XdTujgy0QU1!k+dfmltb-q`28vFb9vx@FUX=|mwoRuz=wd5_+Xm-g{GD^a1B6-y$ zndQi5$!v_IS16n#r`$N+Ul&fAuGdX>Hs;P;B7!x_k24lh@Z2kRNCEl&YnZ)A0T}h$5GkRbIBD z53{qPIgt_1LQzxngJ7zpZ`KCN@hGBux{=UzxVb8QoR<+@aT(+Drmj=AxbQT8N`o#N zU$oJ2NujQaw2|!<`#t zsl1~2jXsyLid|0$PNFNLJJyAa#2{33Fu}=^Z(+vF(QNj1Rwwb2tWV= N5P$##AOHaf{0C9+AV>fJ literal 0 HcmV?d00001 diff --git a/docs/tech-specs/__TEMPLATE.ar.md b/docs/tech-specs/__TEMPLATE.ar.md new file mode 100644 index 00000000..1fde55e8 --- /dev/null +++ b/docs/tech-specs/__TEMPLATE.ar.md @@ -0,0 +1,127 @@ +# المواصفات الفنية لتحميل المعرفة من سطر الأوامر + +## نظرة عامة + +تصف هذه المواصفة واجهات سطر الأوامر لتحميل المعرفة إلى TrustGraph، مما يمكّن المستخدمين من استيراد البيانات من مصادر مختلفة من خلال أدوات سطر الأوامر. تدعم هذه التكامل أربع حالات استخدام رئيسية: + +1. **[حالة الاستخدام 1]**: [الوصف] +2. **[حالة الاستخدام 2]**: [الوصف] +3. **[حالة الاستخدام 3]**: [الوصف] +4. **[حالة الاستخدام 4]**: [الوصف] + +## الأهداف + +- **[الهدف 1]**: [الوصف] +- **[الهدف 2]**: [الوصف] +- **[الهدف 3]**: [الوصف] +- **[الهدف 4]**: [الوصف] +- **[الهدف 5]**: [الوصف] +- **[الهدف 6]**: [الوصف] +- **[الهدف 7]**: [الوصف] +- **[الهدف 8]**: [الوصف] + +## الخلفية + +[صف الحالة الحالية والقيود التي تعالجها هذه المواصفة] + +تشمل القيود الحالية: +- [القيد 1] +- [القيد 2] +- [القيد 3] +- [القيد 4] + +تعالج هذه المواصفة هذه الثغرات من خلال [الوصف]. من خلال [القدرة]، يمكن لـ TrustGraph: +- [الفائدة 1] +- [الفائدة 2] +- [الفائدة 3] +- [الفائدة 4] + +## التصميم الفني + +### البنية + +يتطلب تحميل المعرفة من سطر الأوامر المكونات الفنية التالية: + +1. **[المكون 1]** + - [وصف وظيفة المكون] + - [الميزات الرئيسية] + - [نقاط التكامل] + + الوحدة: [مسار-الوحدة] + +2. **[المكون 2]** + - [وصف وظيفة المكون] + - [الميزات الرئيسية] + - [نقاط التكامل] + + الوحدة: [مسار-الوحدة] + +3. **[المكون 3]** + - [وصف وظيفة المكون] + - [الميزات الرئيسية] + - [نقاط التكامل] + + الوحدة: [مسار-الوحدة] + +### نماذج البيانات + +#### [نموذج البيانات 1] + +[وصف نموذج البيانات والبنية] + +مثال: +``` +[Example data structure] +``` + +هذا النهج يسمح بما يلي: +- [الفائدة 1] +- [الفائدة 2] +- [الفائدة 3] +- [الفائدة 4] + +### واجهات برمجة التطبيقات (APIs) + +واجهات برمجة تطبيقات جديدة: +- [وصف واجهة برمجة التطبيقات 1] +- [وصف واجهة برمجة التطبيقات 2] +- [وصف واجهة برمجة التطبيقات 3] + +واجهات برمجة تطبيقات مُعدَّلة: +- [واجهة برمجة تطبيقات مُعدَّلة 1] - [وصف التغييرات] +- [واجهة برمجة تطبيقات مُعدَّلة 2] - [وصف التغييرات] + +### تفاصيل التنفيذ + +[نهج التنفيذ والاصطلاحات] + +[ملاحظات إضافية حول التنفيذ] + +## اعتبارات الأمان + +[اعتبارات الأمان الخاصة بهذا التنفيذ] + +## اعتبارات الأداء + +[اعتبارات الأداء والاختناقات المحتملة] + +## استراتيجية الاختبار + +[نهج واستراتيجية الاختبار] + +## خطة الترحيل + +[استراتيجية الترحيل إذا كانت قابلة للتطبيق] + +## الجدول الزمني + +[معلومات حول الجدول الزمني إذا تم تحديدها] + +## أسئلة مفتوحة + +- [سؤال مفتوح 1] +- [سؤال مفتوح 2] + +## المراجع + +[المراجع إذا كانت قابلة للتطبيق] diff --git a/docs/tech-specs/__TEMPLATE.es.md b/docs/tech-specs/__TEMPLATE.es.md new file mode 100644 index 00000000..2d4a144e --- /dev/null +++ b/docs/tech-specs/__TEMPLATE.es.md @@ -0,0 +1,127 @@ +# Especificación Técnica de Carga de Conocimiento desde la Línea de Comandos + +## Resumen + +Esta especificación describe las interfaces de línea de comandos para cargar conocimiento en TrustGraph, permitiendo a los usuarios importar datos de diversas fuentes a través de herramientas de línea de comandos. La integración admite cuatro casos de uso principales: + +1. **[Caso de Uso 1]**: [Descripción] +2. **[Caso de Uso 2]**: [Descripción] +3. **[Caso de Uso 3]**: [Descripción] +4. **[Caso de Uso 4]**: [Descripción] + +## Objetivos + +- **[Objetivo 1]**: [Descripción] +- **[Objetivo 2]**: [Descripción] +- **[Objetivo 3]**: [Descripción] +- **[Objetivo 4]**: [Descripción] +- **[Objetivo 5]**: [Descripción] +- **[Objetivo 6]**: [Descripción] +- **[Objetivo 7]**: [Descripción] +- **[Objetivo 8]**: [Descripción] + +## Antecedentes + +[Describa el estado actual y las limitaciones que esta especificación aborda] + +Las limitaciones actuales incluyen: +- [Limitación 1] +- [Limitación 2] +- [Limitación 3] +- [Limitación 4] + +Esta especificación aborda estas deficiencias mediante [descripción]. Al [capacidad], TrustGraph puede: +- [Beneficio 1] +- [Beneficio 2] +- [Beneficio 3] +- [Beneficio 4] + +## Diseño Técnico + +### Arquitectura + +La carga de conocimiento desde la línea de comandos requiere los siguientes componentes técnicos: + +1. **[Componente 1]** + - [Descripción de la funcionalidad del componente] + - [Características clave] + - [Puntos de integración] + + Módulo: [module-path] + +2. **[Componente 2]** + - [Descripción de la funcionalidad del componente] + - [Características clave] + - [Puntos de integración] + + Módulo: [module-path] + +3. **[Componente 3]** + - [Descripción de la funcionalidad del componente] + - [Características clave] + - [Puntos de integración] + + Módulo: [module-path] + +### Modelos de Datos + +#### [Modelo de Datos 1] + +[Descripción del modelo de datos y su estructura] + +Ejemplo: +``` +[Example data structure] +``` + +Este enfoque permite: +- [Beneficio 1] +- [Beneficio 2] +- [Beneficio 3] +- [Beneficio 4] + +### APIs + +Nuevas APIs: +- [Descripción de la API 1] +- [Descripción de la API 2] +- [Descripción de la API 3] + +APIs modificadas: +- [API modificada 1] - [Descripción de los cambios] +- [API modificada 2] - [Descripción de los cambios] + +### Detalles de implementación + +[Enfoque y convenciones de implementación] + +[Notas adicionales de implementación] + +## Consideraciones de seguridad + +[Consideraciones de seguridad específicas de esta implementación] + +## Consideraciones de rendimiento + +[Consideraciones de rendimiento y posibles cuellos de botella] + +## Estrategia de pruebas + +[Enfoque y estrategia de pruebas] + +## Plan de migración + +[Estrategia de migración si es aplicable] + +## Cronograma + +[Información del cronograma si se especifica] + +## Preguntas abiertas + +- [Pregunta abierta 1] +- [Pregunta abierta 2] + +## Referencias + +[Referencias si es aplicable] diff --git a/docs/tech-specs/__TEMPLATE.he.md b/docs/tech-specs/__TEMPLATE.he.md new file mode 100644 index 00000000..5fa1b7d7 --- /dev/null +++ b/docs/tech-specs/__TEMPLATE.he.md @@ -0,0 +1,127 @@ +# Command-Line Loading Knowledge Technical Specification + +## Overview + +מפרט זה מתאר את ממשקי שורת הפקודה לטעינת ידע לתוך TrustGraph, ומאפשר למשתמשים לקלוט נתונים ממקורות שונים באמצעות כלי שורת פקודה. האינטגרציה תומכת בארבעה תרחישי שימוש עיקריים: + +1. **[Use Case 1]**: [Description] +2. **[Use Case 2]**: [Description] +3. **[Use Case 3]**: [Description] +4. **[Use Case 4]**: [Description] + +## Goals + +- **[Goal 1]**: [Description] +- **[Goal 2]**: [Description] +- **[Goal 3]**: [Description] +- **[Goal 4]**: [Description] +- **[Goal 5]**: [Description] +- **[Goal 6]**: [Description] +- **[Goal 7]**: [Description] +- **[Goal 8]**: [Description] + +## Background + +[Describe the current state and limitations that this specification addresses] + +מגבלות נוכחיות כוללות: +- [Limitation 1] +- [Limitation 2] +- [Limitation 3] +- [Limitation 4] + +מפרט זה מתייחס לפערים אלה על ידי [description]. באמצעות [capability], TrustGraph יכול: +- [Benefit 1] +- [Benefit 2] +- [Benefit 3] +- [Benefit 4] + +## Technical Design + +### Architecture + +טעינת ידע משורת הפקודה דורשת את הרכיבים הטכניים הבאים: + +1. **[Component 1]** + - [Description of component functionality] + - [Key features] + - [Integration points] + + Module: [module-path] + +2. **[Component 2]** + - [Description of component functionality] + - [Key features] + - [Integration points] + + Module: [module-path] + +3. **[Component 3]** + - [Description of component functionality] + - [Key features] + - [Integration points] + + Module: [module-path] + +### Data Models + +#### [Data Model 1] + +[Description of data model and structure] + +Example: +``` +[Example data structure] +``` + +גישה זו מאפשרת: +- [Benefit 1] +- [Benefit 2] +- [Benefit 3] +- [Benefit 4] + +### ממשקי API + +ממשקי API חדשים: +- [API description 1] +- [API description 2] +- [API description 3] + +ממשקי API ששונו: +- [Modified API 1] - [Description of changes] +- [Modified API 2] - [Description of changes] + +### פרטי יישום + +[גישת יישום ועקרונות] + +[הערות נוספות בנוגע ליישום] + +## שיקולי אבטחה + +[שיקולי אבטחה ספציפיים ליישום זה] + +## שיקולי ביצועים + +[שיקולי ביצועים וצווארי בקבוק פוטנציאליים] + +## אסטרטגיית בדיקות + +[גישת אסטרטגיית בדיקות] + +## תוכנית מעבר + +[אסטרטגיית מעבר, אם רלוונטית] + +## ציר זמן + +[מידע על ציר הזמן, אם מצוין] + +## שאלות פתוחות + +- [Open question 1] +- [Open question 2] + +## מקורות + +[מקורות, אם רלוונטיים] diff --git a/docs/tech-specs/__TEMPLATE.hi.md b/docs/tech-specs/__TEMPLATE.hi.md new file mode 100644 index 00000000..8089c8e8 --- /dev/null +++ b/docs/tech-specs/__TEMPLATE.hi.md @@ -0,0 +1,127 @@ +# कमांड-लाइन लोडिंग नॉलेज टेक्निकल स्पेसिफिकेशन + +## अवलोकन + +यह स्पेसिफिकेशन ट्रस्टग्राफ में नॉलेज लोड करने के लिए कमांड-लाइन इंटरफेस का वर्णन करता है, जो उपयोगकर्ताओं को कमांड-लाइन टूल के माध्यम से विभिन्न स्रोतों से डेटा प्राप्त करने में सक्षम बनाता है। एकीकरण चार प्राथमिक उपयोग मामलों का समर्थन करता है: + +1. **[उपयोग मामला 1]**: [विवरण] +2. **[उपयोग मामला 2]**: [विवरण] +3. **[उपयोग मामला 3]**: [विवरण] +4. **[उपयोग मामला 4]**: [विवरण] + +## लक्ष्य + +- **[लक्ष्य 1]**: [विवरण] +- **[लक्ष्य 2]**: [विवरण] +- **[लक्ष्य 3]**: [विवरण] +- **[लक्ष्य 4]**: [विवरण] +- **[लक्ष्य 5]**: [विवरण] +- **[लक्ष्य 6]**: [विवरण] +- **[लक्ष्य 7]**: [विवरण] +- **[लक्ष्य 8]**: [विवरण] + +## पृष्ठभूमि + +[वर्तमान स्थिति और सीमाओं का वर्णन करें जिन्हें यह स्पेसिफिकेशन संबोधित करता है] + +वर्तमान सीमाओं में शामिल हैं: +- [सीमा 1] +- [सीमा 2] +- [सीमा 3] +- [सीमा 4] + +यह स्पेसिफिकेशन इन कमियों को [विवरण] द्वारा संबोधित करता है। [क्षमता] के माध्यम से, ट्रस्टग्राफ: +- [लाभ 1] +- [लाभ 2] +- [लाभ 3] +- [लाभ 4] + +## तकनीकी डिजाइन + +### आर्किटेक्चर + +कमांड-लाइन नॉलेज लोडिंग के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: + +1. **[घटक 1]** + - [घटक कार्यक्षमता का विवरण] + - [मुख्य विशेषताएं] + - [एकीकरण बिंदु] + + मॉड्यूल: [मॉड्यूल-पाथ] + +2. **[घटक 2]** + - [घटक कार्यक्षमता का विवरण] + - [मुख्य विशेषताएं] + - [एकीकरण बिंदु] + + मॉड्यूल: [मॉड्यूल-पाथ] + +3. **[घटक 3]** + - [घटक कार्यक्षमता का विवरण] + - [मुख्य विशेषताएं] + - [एकीकरण बिंदु] + + मॉड्यूल: [मॉड्यूल-पाथ] + +### डेटा मॉडल + +#### [डेटा मॉडल 1] + +[डेटा मॉडल और संरचना का विवरण] + +उदाहरण: +``` +[Example data structure] +``` + +यह दृष्टिकोण निम्नलिखित की अनुमति देता है: +- [लाभ 1] +- [लाभ 2] +- [लाभ 3] +- [लाभ 4] + +### एपीआई (APIs) + +नए एपीआई (APIs): +- [एपीआई विवरण 1] +- [एपीआई विवरण 2] +- [एपीआई विवरण 3] + +संशोधित एपीआई (APIs): +- [संशोधित एपीआई 1] - [परिवर्तनों का विवरण] +- [संशोधित एपीआई 2] - [परिवर्तनों का विवरण] + +### कार्यान्वयन विवरण + +[कार्यान्वयन दृष्टिकोण और परंपराएं] + +[अतिरिक्त कार्यान्वयन नोट्स] + +## सुरक्षा संबंधी विचार + +[इस कार्यान्वयन के लिए विशिष्ट सुरक्षा संबंधी विचार] + +## प्रदर्शन संबंधी विचार + +[प्रदर्शन संबंधी विचार और संभावित बाधाएं] + +## परीक्षण रणनीति + +[परीक्षण दृष्टिकोण और रणनीति] + +## माइग्रेशन योजना + +[यदि लागू हो, तो माइग्रेशन रणनीति] + +## समयरेखा + +[यदि निर्दिष्ट किया गया है, तो समयरेखा जानकारी] + +## अनुत्तरित प्रश्न + +- [अनुत्तरित प्रश्न 1] +- [अनुत्तरित प्रश्न 2] + +## संदर्भ + +[यदि लागू हो, तो संदर्भ] diff --git a/docs/tech-specs/__TEMPLATE.pt.md b/docs/tech-specs/__TEMPLATE.pt.md new file mode 100644 index 00000000..9f04173d --- /dev/null +++ b/docs/tech-specs/__TEMPLATE.pt.md @@ -0,0 +1,127 @@ +# Especificação Técnica de Carregamento de Conhecimento via Linha de Comando + +## Visão Geral + +Esta especificação descreve as interfaces de linha de comando para carregar conhecimento no TrustGraph, permitindo que os usuários ingiram dados de várias fontes por meio de ferramentas de linha de comando. A integração suporta quatro casos de uso primários: + +1. **[Caso de Uso 1]**: [Descrição] +2. **[Caso de Uso 2]**: [Descrição] +3. **[Caso de Uso 3]**: [Descrição] +4. **[Caso de Uso 4]**: [Descrição] + +## Objetivos + +- **[Objetivo 1]**: [Descrição] +- **[Objetivo 2]**: [Descrição] +- **[Objetivo 3]**: [Descrição] +- **[Objetivo 4]**: [Descrição] +- **[Objetivo 5]**: [Descrição] +- **[Objetivo 6]**: [Descrição] +- **[Objetivo 7]**: [Descrição] +- **[Objetivo 8]**: [Descrição] + +## Contexto + +[Descreva o estado atual e as limitações que esta especificação aborda] + +As limitações atuais incluem: +- [Limitação 1] +- [Limitação 2] +- [Limitação 3] +- [Limitação 4] + +Esta especificação aborda essas lacunas ao [descrição]. Ao [capacidade], o TrustGraph pode: +- [Benefício 1] +- [Benefício 2] +- [Benefício 3] +- [Benefício 4] + +## Design Técnico + +### Arquitetura + +O carregamento de conhecimento via linha de comando requer os seguintes componentes técnicos: + +1. **[Componente 1]** + - [Descrição da funcionalidade do componente] + - [Características principais] + - [Pontos de integração] + + Módulo: [caminho-do-módulo] + +2. **[Componente 2]** + - [Descrição da funcionalidade do componente] + - [Características principais] + - [Pontos de integração] + + Módulo: [caminho-do-módulo] + +3. **[Componente 3]** + - [Descrição da funcionalidade do componente] + - [Características principais] + - [Pontos de integração] + + Módulo: [caminho-do-módulo] + +### Modelos de Dados + +#### [Modelo de Dados 1] + +[Descrição do modelo de dados e estrutura] + +Exemplo: +``` +[Example data structure] +``` + +Esta abordagem permite: +- [Benefício 1] +- [Benefício 2] +- [Benefício 3] +- [Benefício 4] + +### APIs + +Novas APIs: +- [Descrição da API 1] +- [Descrição da API 2] +- [Descrição da API 3] + +APIs modificadas: +- [API modificada 1] - [Descrição das alterações] +- [API modificada 2] - [Descrição das alterações] + +### Detalhes de implementação + +[Abordagem e convenções de implementação] + +[Notas adicionais de implementação] + +## Considerações de segurança + +[Considerações de segurança específicas para esta implementação] + +## Considerações de desempenho + +[Considerações de desempenho e possíveis gargalos] + +## Estratégia de testes + +[Abordagem e estratégia de testes] + +## Plano de migração + +[Estratégia de migração, se aplicável] + +## Cronograma + +[Informações sobre o cronograma, se especificadas] + +## Perguntas pendentes + +- [Pergunta pendente 1] +- [Pergunta pendente 2] + +## Referências + +[Referências, se aplicável] diff --git a/docs/tech-specs/__TEMPLATE.ru.md b/docs/tech-specs/__TEMPLATE.ru.md new file mode 100644 index 00000000..5c42d908 --- /dev/null +++ b/docs/tech-specs/__TEMPLATE.ru.md @@ -0,0 +1,127 @@ +# Техническая спецификация загрузки знаний через командную строку + +## Обзор + +Эта спецификация описывает интерфейсы командной строки для загрузки знаний в TrustGraph, позволяя пользователям загружать данные из различных источников с помощью инструментов командной строки. Интеграция поддерживает четыре основных сценария использования: + +1. **[Сценарий использования 1]**: [Описание] +2. **[Сценарий использования 2]**: [Описание] +3. **[Сценарий использования 3]**: [Описание] +4. **[Сценарий использования 4]**: [Описание] + +## Цели + +- **[Цель 1]**: [Описание] +- **[Цель 2]**: [Описание] +- **[Цель 3]**: [Описание] +- **[Цель 4]**: [Описание] +- **[Цель 5]**: [Описание] +- **[Цель 6]**: [Описание] +- **[Цель 7]**: [Описание] +- **[Цель 8]**: [Описание] + +## Предыстория + +[Опишите текущее состояние и ограничения, которые решает эта спецификация] + +Текущие ограничения включают: +- [Ограничение 1] +- [Ограничение 2] +- [Ограничение 3] +- [Ограничение 4] + +Эта спецификация устраняет эти недостатки, [описание]. Благодаря [возможности], TrustGraph может: +- [Преимущество 1] +- [Преимущество 2] +- [Преимущество 3] +- [Преимущество 4] + +## Технический дизайн + +### Архитектура + +Загрузка знаний через командную строку требует следующих технических компонентов: + +1. **[Компонент 1]** + - [Описание функциональности компонента] + - [Основные характеристики] + - [Точки интеграции] + + Модуль: [путь_к_модулю] + +2. **[Компонент 2]** + - [Описание функциональности компонента] + - [Основные характеристики] + - [Точки интеграции] + + Модуль: [путь_к_модулю] + +3. **[Компонент 3]** + - [Описание функциональности компонента] + - [Основные характеристики] + - [Точки интеграции] + + Модуль: [путь_к_модулю] + +### Модели данных + +#### [Модель данных 1] + +[Описание модели данных и ее структуры] + +Пример: +``` +[Example data structure] +``` + +Этот подход позволяет: +- [Преимущество 1] +- [Преимущество 2] +- [Преимущество 3] +- [Преимущество 4] + +### API + +Новые API: +- [Описание API 1] +- [Описание API 2] +- [Описание API 3] + +Измененные API: +- [Измененный API 1] - [Описание изменений] +- [Измененный API 2] - [Описание изменений] + +### Детали реализации + +[Подход к реализации и соглашения] + +[Дополнительные примечания по реализации] + +## Вопросы безопасности + +[Вопросы безопасности, специфичные для данной реализации] + +## Вопросы производительности + +[Вопросы производительности и потенциальные узкие места] + +## Стратегия тестирования + +[Подход и стратегия тестирования] + +## План миграции + +[Стратегия миграции, если применимо] + +## Сроки + +[Информация о сроках, если указана] + +## Открытые вопросы + +- [Открытый вопрос 1] +- [Открытый вопрос 2] + +## Ссылки + +[Ссылки, если применимо] diff --git a/docs/tech-specs/__TEMPLATE.sw.md b/docs/tech-specs/__TEMPLATE.sw.md new file mode 100644 index 00000000..c7df83e3 --- /dev/null +++ b/docs/tech-specs/__TEMPLATE.sw.md @@ -0,0 +1,127 @@ +# Vipimo vya Kiufundi vya Kujaza Habari Kupitia Amri ya Kamba + +## Muhtasari + +Vipimo hivi vinaelezea interface za amri ya kamba kwa ajili ya kujaza habari katika TrustGraph, na kuwezesha watumiaji kusambaza data kutoka vyanzo mbalimbali kupitia zana za amri ya kamba. Uunganishaji huu unaunga mkono matumizi manne makuu: + +1. **[Matumizi ya 1]**: [Maelezo] +2. **[Matumizi ya 2]**: [Maelezo] +3. **[Matumizi ya 3]**: [Maelezo] +4. **[Matumizi ya 4]**: [Maelezo] + +## Lengo + +- **[Lengo la 1]**: [Maelezo] +- **[Lengo la 2]**: [Maelezo] +- **[Lengo la 3]**: [Maelezo] +- **[Lengo la 4]**: [Maelezo] +- **[Lengo la 5]**: [Maelezo] +- **[Lengo la 6]**: [Maelezo] +- **[Lengo la 7]**: [Maelezo] +- **[Lengo la 8]**: [Maelezo] + +## Asili + +[Eleza hali ya sasa na vikwazo ambavyo vipimo hivi vinashughulikia] + +Vikwazo vya sasa ni pamoja na: +- [Vikwazo 1] +- [Vikwazo 2] +- [Vikwazo 3] +- [Vikwazo 4] + +Vipimo hivi vinashughulikia pengo hizi kwa [maelezo]. Kwa [uwezo], TrustGraph inaweza: +- [Faida 1] +- [Faida 2] +- [Faida 3] +- [Faida 4] + +## Muundo wa Kiufundi + +### Usanifu + +Kujaza habari kupitia amri ya kamba inahitaji vipengele vifuatavyo vya kiufundi: + +1. **[Kipengele cha 1]** + - [Maelezo ya utendaji wa kipengele] + - [Sifa muhimu] + - [Maeneo ya kuunganisha] + + Moduli: [njia-ya-moduli] + +2. **[Kipengele cha 2]** + - [Maelezo ya utendaji wa kipengele] + - [Sifa muhimu] + - [Maeneo ya kuunganisha] + + Moduli: [njia-ya-moduli] + +3. **[Kipengele cha 3]** + - [Maelezo ya utendaji wa kipengele] + - [Sifa muhimu] + - [Maeneo ya kuunganisha] + + Moduli: [njia-ya-moduli] + +### Mifano ya Data + +#### [Mifano ya Data 1] + +[Maelezo ya mfano wa data na muundo] + +Mfano: +``` +[Example data structure] +``` + +Mbinu hii inaruhusu: +- [Faida 1] +- [Faida 2] +- [Faida 3] +- [Faida 4] + +### API + +API mpya: +- [Maelezo ya API 1] +- [Maelezo ya API 2] +- [Maelezo ya API 3] + +API zilizobadilishwa: +- [API iliyobadilishwa 1] - [Maelezo ya mabadiliko] +- [API iliyobadilishwa 2] - [Maelezo ya mabadiliko] + +### Maelezo ya Utendaji + +[Mbinu na miongozo ya utendaji] + +[Maelezo ya ziada ya utendaji] + +## Masuala ya Usalama + +[Masuala ya usalama maalum kwa utendaji huu] + +## Masuala ya Utendaji + +[Masuala ya utendaji na vizuizi vinavyowezekana] + +## Mkakati wa Majaribio + +[Mbinu na mkakati wa majaribio] + +## Mpango wa Uhamisho + +[Mkakati wa uhamisho ikiwa unafaa] + +## Ratiba + +[Habari ya ratiba ikiwa imebainishwa] + +## Maswali Yaliyobaki + +- [Swali lililobaki 1] +- [Swali lililobaki 2] + +## Marejeleo + +[Marejeleo ikiwa yanafaa] diff --git a/docs/tech-specs/__TEMPLATE.tr.md b/docs/tech-specs/__TEMPLATE.tr.md new file mode 100644 index 00000000..584e07f4 --- /dev/null +++ b/docs/tech-specs/__TEMPLATE.tr.md @@ -0,0 +1,127 @@ +# Komut Satırı ile Bilgi Yükleme Teknik Özellikleri + +## Genel Bakış + +Bu teknik özellik, TrustGraph'a bilgi yüklemek için komut satırı arayüzlerini tanımlar ve kullanıcıların komut satırı araçları aracılığıyla çeşitli kaynaklardan veri almasını sağlar. Bu entegrasyon, dört ana kullanım senaryosunu destekler: + +1. **[Kullanım Senaryosu 1]**: [Açıklama] +2. **[Kullanım Senaryosu 2]**: [Açıklama] +3. **[Kullanım Senaryosu 3]**: [Açıklama] +4. **[Kullanım Senaryosu 4]**: [Açıklama] + +## Hedefler + +- **[Hedef 1]**: [Açıklama] +- **[Hedef 2]**: [Açıklama] +- **[Hedef 3]**: [Açıklama] +- **[Hedef 4]**: [Açıklama] +- **[Hedef 5]**: [Açıklama] +- **[Hedef 6]**: [Açıklama] +- **[Hedef 7]**: [Açıklama] +- **[Hedef 8]**: [Açıklama] + +## Arka Plan + +[Mevcut durumu ve bu teknik özelliğin ele aldığı sınırlamaları açıklayın] + +Mevcut sınırlamalar şunlardır: +- [Sınırlama 1] +- [Sınırlama 2] +- [Sınırlama 3] +- [Sınırlama 4] + +Bu teknik özellik, bu eksiklikleri [açıklama] ile giderir. [Yeteneği] sayesinde, TrustGraph şunları yapabilir: +- [Fayda 1] +- [Fayda 2] +- [Fayda 3] +- [Fayda 4] + +## Teknik Tasarım + +### Mimari + +Komut satırı ile bilgi yükleme, aşağıdaki teknik bileşenleri gerektirir: + +1. **[Bileşen 1]** + - [Bileşenin işlevselliğinin açıklaması] + - [Temel özellikler] + - [Entegrasyon noktaları] + + Modül: [modül-yolu] + +2. **[Bileşen 2]** + - [Bileşenin işlevselliğinin açıklaması] + - [Temel özellikler] + - [Entegrasyon noktaları] + + Modül: [modül-yolu] + +3. **[Bileşen 3]** + - [Bileşenin işlevselliğinin açıklaması] + - [Temel özellikler] + - [Entegrasyon noktaları] + + Modül: [modül-yolu] + +### Veri Modelleri + +#### [Veri Modeli 1] + +[Veri modelinin ve yapısının açıklaması] + +Örnek: +``` +[Example data structure] +``` + +Bu yaklaşım şunları sağlar: +- [Fayda 1] +- [Fayda 2] +- [Fayda 3] +- [Fayda 4] + +### API'ler + +Yeni API'ler: +- [API açıklaması 1] +- [API açıklaması 2] +- [API açıklaması 3] + +Değiştirilen API'ler: +- [Değiştirilen API 1] - [Değişikliklerin açıklaması] +- [Değiştirilen API 2] - [Değişikliklerin açıklaması] + +### Uygulama Detayları + +[Uygulama yaklaşımı ve kurallar] + +[Ek uygulama notları] + +## Güvenlik Hususları + +[Bu uygulamanın özel güvenlik hususları] + +## Performans Hususları + +[Performans hususları ve olası darboğazlar] + +## Test Stratejisi + +[Test yaklaşımı ve stratejisi] + +## Geçiş Planı + +[Gerekliyse geçiş stratejisi] + +## Zaman Çizelgesi + +[Belirtilmişse zaman çizelgesi bilgileri] + +## Açık Sorular + +- [Açık soru 1] +- [Açık soru 2] + +## Referanslar + +[Gerekliyse referanslar] diff --git a/docs/tech-specs/__TEMPLATE.zh-cn.md b/docs/tech-specs/__TEMPLATE.zh-cn.md new file mode 100644 index 00000000..6219c246 --- /dev/null +++ b/docs/tech-specs/__TEMPLATE.zh-cn.md @@ -0,0 +1,127 @@ +# 命令行加载知识的技术规范 + +## 概述 + +本规范描述了用于将知识加载到 TrustGraph 的命令行接口,使用户能够通过命令行工具从各种来源导入数据。该集成支持四个主要用例: + +1. **[用例 1]**: [描述] +2. **[用例 2]**: [描述] +3. **[用例 3]**: [描述] +4. **[用例 4]**: [描述] + +## 目标 + +- **[目标 1]**: [描述] +- **[目标 2]**: [描述] +- **[目标 3]**: [描述] +- **[目标 4]**: [描述] +- **[目标 5]**: [描述] +- **[目标 6]**: [描述] +- **[目标 7]**: [描述] +- **[目标 8]**: [描述] + +## 背景 + +[描述当前状态以及本规范所解决的限制] + +当前的限制包括: +- [限制 1] +- [限制 2] +- [限制 3] +- [限制 4] + +本规范通过 [描述] 解决了这些差距。 通过 [功能],TrustGraph 可以: +- [优势 1] +- [优势 2] +- [优势 3] +- [优势 4] + +## 技术设计 + +### 架构 + +命令行知识加载需要以下技术组件: + +1. **[组件 1]** + - [组件功能描述] + - [主要特性] + - [集成点] + + 模块: [module-path] + +2. **[组件 2]** + - [组件功能描述] + - [主要特性] + - [集成点] + + 模块: [module-path] + +3. **[组件 3]** + - [组件功能描述] + - [主要特性] + - [集成点] + + 模块: [module-path] + +### 数据模型 + +#### [数据模型 1] + +[数据模型和结构的描述] + +示例: +``` +[Example data structure] +``` + +这种方法允许: +- [Benefit 1] +- [Benefit 2] +- [Benefit 3] +- [Benefit 4] + +### APIs + +新的 API: +- [API description 1] +- [API description 2] +- [API description 3] + +修改后的 API: +- [Modified API 1] - [Description of changes] +- [Modified API 2] - [Description of changes] + +### 实现细节 + +[Implementation approach and conventions] + +[Additional implementation notes] + +## 安全性考虑 + +[Security considerations specific to this implementation] + +## 性能考虑 + +[Performance considerations and potential bottlenecks] + +## 测试策略 + +[Testing approach and strategy] + +## 迁移计划 + +[Migration strategy if applicable] + +## 时间线 + +[Timeline information if specified] + +## 待解决问题 + +- [Open question 1] +- [Open question 2] + +## 参考文献 + +[References if applicable] diff --git a/docs/tech-specs/agent-explainability.ar.md b/docs/tech-specs/agent-explainability.ar.md new file mode 100644 index 00000000..6b2be71c --- /dev/null +++ b/docs/tech-specs/agent-explainability.ar.md @@ -0,0 +1,272 @@ +# شرح عمل الوكيل: تسجيل المصدر + +## نظرة عامة + +أضف تسجيل المصدر إلى حلقة الوكيل في React حتى يمكن تتبع جلسات الوكيل وتصحيحها باستخدام نفس البنية التحتية للشرح كما هو الحال في GraphRAG. + +**قرارات التصميم:** +الكتابة إلى `urn:graph:retrieval` (رسم بياني للشرح العام) +سلسلة اعتماد خطية في الوقت الحالي (تحليل N → تم اشتقاقه من → تحليل N-1) +الأدوات هي صناديق سوداء (تسجيل الإدخال/الإخراج فقط) +دعم الرسم البياني الموجه غير المتصل (DAG) مؤجل للتكرار المستقبلي + +## أنواع الكيانات + +يستخدم كل من GraphRAG والوكيل PROV-O كعلم الوجود الأساسي مع أنواع فرعية خاصة بـ TrustGraph: + +### أنواع GraphRAG +| الكيان | نوع PROV-O | أنواع TG | الوصف | +|--------|-------------|----------|-------------| +| سؤال | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | استعلام المستخدم | +| استكشاف | `prov:Entity` | `tg:Exploration` | الحواف المستردة من الرسم البياني المعرفي | +| تركيز | `prov:Entity` | `tg:Focus` | الحواف المحددة مع الاستدلال | +| توليف | `prov:Entity` | `tg:Synthesis` | الإجابة النهائية | + +### أنواع الوكيل +| الكيان | نوع PROV-O | أنواع TG | الوصف | +|--------|-------------|----------|-------------| +| سؤال | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | استعلام المستخدم | +| تحليل | `prov:Entity` | `tg:Analysis` | كل دورة تفكير/فعل/ملاحظة | +| استنتاج | `prov:Entity` | `tg:Conclusion` | الإجابة النهائية | + +### أنواع RAG للوثائق +| الكيان | نوع PROV-O | أنواع TG | الوصف | +|--------|-------------|----------|-------------| +| سؤال | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | استعلام المستخدم | +| استكشاف | `prov:Entity` | `tg:Exploration` | أجزاء مستردة من مستودع المستندات | +| توليف | `prov:Entity` | `tg:Synthesis` | الإجابة النهائية | + +**ملاحظة:** يستخدم RAG للوثائق مجموعة فرعية من أنواع GraphRAG (لا توجد خطوة "تركيز" نظرًا لعدم وجود مرحلة اختيار/استدلال للحواف). + +### أنواع فرعية للأسئلة + +تشترك جميع كيانات "سؤال" في `tg:Question` كنوع أساسي ولكنها تحتوي على نوع فرعي محدد لتحديد آلية الاسترداد: + +| النوع الفرعي | نمط URI | الآلية | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | RAG للرسم البياني المعرفي | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | RAG للوثائق/الأجزاء | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | وكيل ReAct | + +يتيح ذلك الاستعلام عن جميع الأسئلة عبر `tg:Question` مع التصفية حسب آلية معينة عبر النوع الفرعي. + +## نموذج المصدر + +``` +Question (urn:trustgraph:agent:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasDerivedFrom + │ +Analysis1 (urn:trustgraph:agent:{uuid}/i1) + │ + │ tg:thought = "I need to query the knowledge base..." + │ tg:action = "knowledge-query" + │ tg:arguments = {"question": "..."} + │ tg:observation = "Result from tool..." + │ rdf:type = prov:Entity, tg:Analysis + │ + ↓ prov:wasDerivedFrom + │ +Analysis2 (urn:trustgraph:agent:{uuid}/i2) + │ ... + ↓ prov:wasDerivedFrom + │ +Conclusion (urn:trustgraph:agent:{uuid}/final) + │ + │ tg:answer = "The final response..." + │ rdf:type = prov:Entity, tg:Conclusion +``` + +### نموذج تتبع أصل المستندات (Document RAG Provenance Model) + +``` +Question (urn:trustgraph:docrag:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasGeneratedBy + │ +Exploration (urn:trustgraph:docrag:{uuid}/exploration) + │ + │ tg:chunkCount = 5 + │ tg:selectedChunk = "chunk-id-1" + │ tg:selectedChunk = "chunk-id-2" + │ ... + │ rdf:type = prov:Entity, tg:Exploration + │ + ↓ prov:wasDerivedFrom + │ +Synthesis (urn:trustgraph:docrag:{uuid}/synthesis) + │ + │ tg:content = "The synthesized answer..." + │ rdf:type = prov:Entity, tg:Synthesis +``` + +## التغييرات المطلوبة + +### 1. تغييرات المخطط + +**الملف:** `trustgraph-base/trustgraph/schema/services/agent.py` + +أضف الحقول `session_id` و `collection` إلى `AgentRequest`: +```python +@dataclass +class AgentRequest: + question: str = "" + state: str = "" + group: list[str] | None = None + history: list[AgentStep] = field(default_factory=list) + user: str = "" + collection: str = "default" # NEW: Collection for provenance traces + streaming: bool = False + session_id: str = "" # NEW: For provenance tracking across iterations +``` + +**الملف:** `trustgraph-base/trustgraph/messaging/translators/agent.py` + +تحديث المترجم للتعامل مع `session_id` و `collection` في كل من `to_pulsar()` و `from_pulsar()`. + +### 2. إضافة مُنتج الشفافية إلى خدمة الوكيل + +**الملف:** `trustgraph-flow/trustgraph/agent/react/service.py` + +تسجيل مُنتج "الشفافية" (بنفس النمط مثل GraphRAG): +```python +from ... base import ProducerSpec +from ... schema import Triples + +# In __init__: +self.register_specification( + ProducerSpec( + name = "explainability", + schema = Triples, + ) +) +``` + +### 3. توليد الثلاثيات المتعلقة بالأصل. + +**الملف:** `trustgraph-base/trustgraph/provenance/agent.py` + +إنشاء دوال مساعدة (مشابهة لدوال `question_triples` و `exploration_triples`، إلخ في GraphRAG): +```python +def agent_session_triples(session_uri, query, timestamp): + """Generate triples for agent Question.""" + return [ + Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY), + Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION), + Triple(s=session_uri, p=TG_QUERY, o=query), + Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp), + ] + +def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation): + """Generate triples for one Analysis step.""" + return [ + Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS), + Triple(s=iteration_uri, p=TG_THOUGHT, o=thought), + Triple(s=iteration_uri, p=TG_ACTION, o=action), + Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)), + Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation), + Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] + +def agent_final_triples(final_uri, parent_uri, answer): + """Generate triples for Conclusion.""" + return [ + Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION), + Triple(s=final_uri, p=TG_ANSWER, o=answer), + Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] +``` + +### 4. تعريفات الأنواع + +**الملف:** `trustgraph-base/trustgraph/provenance/namespaces.py` + +أضف أنواع الكيانات الخاصة بالتفسير والعبارات الخاصة بالوكيل: +```python +# Explainability entity types (used by both GraphRAG and Agent) +TG_QUESTION = TG + "Question" +TG_EXPLORATION = TG + "Exploration" +TG_FOCUS = TG + "Focus" +TG_SYNTHESIS = TG + "Synthesis" +TG_ANALYSIS = TG + "Analysis" +TG_CONCLUSION = TG + "Conclusion" + +# Agent predicates +TG_THOUGHT = TG + "thought" +TG_ACTION = TG + "action" +TG_ARGUMENTS = TG + "arguments" +TG_OBSERVATION = TG + "observation" +TG_ANSWER = TG + "answer" +``` + +## الملفات التي تم تعديلها + +| الملف | التغيير | +|------|--------| +| `trustgraph-base/trustgraph/schema/services/agent.py` | إضافة session_id و collection إلى AgentRequest | +| `trustgraph-base/trustgraph/messaging/translators/agent.py` | تحديث المترجم للحقول الجديدة | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | إضافة أنواع الكيانات، وعبارات الوكيل، وأنواع Document RAG | +| `trustgraph-base/trustgraph/provenance/triples.py` | إضافة أنواع TG إلى أدوات بناء الثلاثيات GraphRAG، وإضافة أدوات بناء الثلاثيات Document RAG | +| `trustgraph-base/trustgraph/provenance/uris.py` | إضافة مولدات URI لـ Document RAG | +| `trustgraph-base/trustgraph/provenance/__init__.py` | تصدير الأنواع والعبارات الجديدة ووظائف Document RAG | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | إضافة explain_id و explain_graph إلى DocumentRagResponse | +| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | تحديث DocumentRagResponseTranslator للحقول الخاصة بالقدرة على الشرح | +| `trustgraph-flow/trustgraph/agent/react/service.py` | إضافة منطق الإنتاج والتسجيل الخاص بالقدرة على الشرح | +| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | إضافة استدعاء رد (callback) خاص بالقدرة على الشرح وإصدار ثلاثيات المصدر | +| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | إضافة مُنتج القدرة على الشرح وربطه بالاستدعاء الردي | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | معالجة أنواع تتبع الوكيل | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | عرض جلسات الوكيل جنبًا إلى جنب مع GraphRAG | + +## الملفات التي تم إنشاؤها + +| الملف | الغرض | +|------|---------| +| `trustgraph-base/trustgraph/provenance/agent.py` | مولدات ثلاثيات خاصة بالوكيل | + +## تحديثات واجهة سطر الأوامر (CLI) + +**الكشف:** كل من GraphRAG والأسئلة الخاصة بالوكيل لهما نوع `tg:Question`. يتم التمييز بينهما بواسطة: +1. نمط URI: `urn:trustgraph:agent:` مقابل `urn:trustgraph:question:` +2. الكيانات المشتقة: `tg:Analysis` (الوكيل) مقابل `tg:Exploration` (GraphRAG) + +**`list_explain_traces.py`:** +يعرض عمود النوع (الوكيل مقابل GraphRAG) + +**`show_explain_trace.py`:** +يكتشف تلقائيًا نوع التتبع +يعرض عرض الوكيل: سؤال → خطوة(ات) تحليل → استنتاج + +## التوافق مع الإصدارات السابقة + +`session_id` افتراضيًا إلى `""` - تعمل الطلبات القديمة، ولكن لن تحتوي على معلومات المصدر | +`collection` افتراضيًا إلى `"default"` - حل بديل معقول | +تتعامل واجهة سطر الأوامر (CLI) بأمان مع كلا نوعي التتبع | + +## التحقق + +```bash +# Run an agent query +tg-invoke-agent -q "What is the capital of France?" + +# List traces (should show agent sessions with Type column) +tg-list-explain-traces -U trustgraph -C default + +# Show agent trace +tg-show-explain-trace "urn:trustgraph:agent:xxx" +``` + +## الأعمال المستقبلية (ليست جزءًا من هذا التعديل) + +تبعيات الرسم البياني الموجه (عندما يعتمد التحليل N على نتائج تحليلات سابقة متعددة) +ربط المصادر الخاص بالأدوات (KnowledgeQuery ← تتبع GraphRAG الخاص به) +إرسال المصادر بشكل مستمر (إرسال البيانات أثناء العمل، وليس دفعة واحدة في النهاية) diff --git a/docs/tech-specs/agent-explainability.es.md b/docs/tech-specs/agent-explainability.es.md new file mode 100644 index 00000000..6ad9b38d --- /dev/null +++ b/docs/tech-specs/agent-explainability.es.md @@ -0,0 +1,272 @@ +# Explicabilidad del Agente: Registro de Origen + +## Resumen + +Agregar el registro de origen al bucle del agente de React para que las sesiones del agente puedan ser rastreadas y depuradas utilizando la misma infraestructura de explicabilidad que GraphRAG. + +**Decisiones de Diseño:** +- Escribir en `urn:graph:retrieval` (grafo de explicabilidad genérico) +- Cadena de dependencia lineal por ahora (análisis N → derivado de → análisis N-1) +- Las herramientas son cajas negras opacas (registrar solo la entrada/salida) +- El soporte de DAG se pospone a una iteración futura + +## Tipos de Entidades + +Tanto GraphRAG como Agent utilizan PROV-O como la ontología base con subtipos específicos de TrustGraph: + +### Tipos de GraphRAG +| Entidad | Tipo PROV-O | Tipos TG | Descripción | +|--------|-------------|----------|-------------| +| Pregunta | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | La consulta del usuario | +| Exploración | `prov:Entity` | `tg:Exploration` | Bordes recuperados del grafo de conocimiento | +| Enfoque | `prov:Entity` | `tg:Focus` | Bordes seleccionados con razonamiento | +| Síntesis | `prov:Entity` | `tg:Synthesis` | Respuesta final | + +### Tipos de Agente +| Entidad | Tipo PROV-O | Tipos TG | Descripción | +|--------|-------------|----------|-------------| +| Pregunta | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | La consulta del usuario | +| Análisis | `prov:Entity` | `tg:Analysis` | Cada ciclo de pensar/actuar/observar | +| Conclusión | `prov:Entity` | `tg:Conclusion` | Respuesta final | + +### Tipos de Document RAG +| Entidad | Tipo PROV-O | Tipos TG | Descripción | +|--------|-------------|----------|-------------| +| Pregunta | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | La consulta del usuario | +| Exploración | `prov:Entity` | `tg:Exploration` | Fragmentos recuperados del almacén de documentos | +| Síntesis | `prov:Entity` | `tg:Synthesis` | Respuesta final | + +**Nota:** Document RAG utiliza un subconjunto de los tipos de GraphRAG (no hay un paso de "Enfoque" ya que no hay una fase de selección/razonamiento de bordes). + +### Subtipos de Pregunta + +Todas las entidades de "Pregunta" comparten `tg:Question` como un tipo base, pero tienen un subtipo específico para identificar el mecanismo de recuperación: + +| Subtipo | Patrón URI | Mecanismo | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | RAG de grafo de conocimiento | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | RAG de documento/fragmento | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | Agente ReAct | + +Esto permite consultar todas las preguntas a través de `tg:Question` mientras se filtra por un mecanismo específico a través del subtipo. + +## Modelo de Origen + +``` +Question (urn:trustgraph:agent:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasDerivedFrom + │ +Analysis1 (urn:trustgraph:agent:{uuid}/i1) + │ + │ tg:thought = "I need to query the knowledge base..." + │ tg:action = "knowledge-query" + │ tg:arguments = {"question": "..."} + │ tg:observation = "Result from tool..." + │ rdf:type = prov:Entity, tg:Analysis + │ + ↓ prov:wasDerivedFrom + │ +Analysis2 (urn:trustgraph:agent:{uuid}/i2) + │ ... + ↓ prov:wasDerivedFrom + │ +Conclusion (urn:trustgraph:agent:{uuid}/final) + │ + │ tg:answer = "The final response..." + │ rdf:type = prov:Entity, tg:Conclusion +``` + +### Modelo de Origen (Provenance) del Documento RAG + +``` +Question (urn:trustgraph:docrag:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasGeneratedBy + │ +Exploration (urn:trustgraph:docrag:{uuid}/exploration) + │ + │ tg:chunkCount = 5 + │ tg:selectedChunk = "chunk-id-1" + │ tg:selectedChunk = "chunk-id-2" + │ ... + │ rdf:type = prov:Entity, tg:Exploration + │ + ↓ prov:wasDerivedFrom + │ +Synthesis (urn:trustgraph:docrag:{uuid}/synthesis) + │ + │ tg:content = "The synthesized answer..." + │ rdf:type = prov:Entity, tg:Synthesis +``` + +## Cambios Requeridos + +### 1. Cambios en el Esquema + +**Archivo:** `trustgraph-base/trustgraph/schema/services/agent.py` + +Agregar los campos `session_id` y `collection` a `AgentRequest`: +```python +@dataclass +class AgentRequest: + question: str = "" + state: str = "" + group: list[str] | None = None + history: list[AgentStep] = field(default_factory=list) + user: str = "" + collection: str = "default" # NEW: Collection for provenance traces + streaming: bool = False + session_id: str = "" # NEW: For provenance tracking across iterations +``` + +**Archivo:** `trustgraph-base/trustgraph/messaging/translators/agent.py` + +Actualizar el traductor para manejar `session_id` y `collection` tanto en `to_pulsar()` como en `from_pulsar()`. + +### 2. Agregar un Productor de Explicabilidad al Servicio de Agente + +**Archivo:** `trustgraph-flow/trustgraph/agent/react/service.py` + +Registrar un productor de "explicabilidad" (mismo patrón que GraphRAG): +```python +from ... base import ProducerSpec +from ... schema import Triples + +# In __init__: +self.register_specification( + ProducerSpec( + name = "explainability", + schema = Triples, + ) +) +``` + +### 3. Generación de Triples de Proveniencia + +**Archivo:** `trustgraph-base/trustgraph/provenance/agent.py` + +Crear funciones auxiliares (similares a `question_triples`, `exploration_triples`, etc. de GraphRAG): +```python +def agent_session_triples(session_uri, query, timestamp): + """Generate triples for agent Question.""" + return [ + Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY), + Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION), + Triple(s=session_uri, p=TG_QUERY, o=query), + Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp), + ] + +def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation): + """Generate triples for one Analysis step.""" + return [ + Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS), + Triple(s=iteration_uri, p=TG_THOUGHT, o=thought), + Triple(s=iteration_uri, p=TG_ACTION, o=action), + Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)), + Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation), + Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] + +def agent_final_triples(final_uri, parent_uri, answer): + """Generate triples for Conclusion.""" + return [ + Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION), + Triple(s=final_uri, p=TG_ANSWER, o=answer), + Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] +``` + +### 4. Definiciones de tipo + +**Archivo:** `trustgraph-base/trustgraph/provenance/namespaces.py` + +Agregar tipos de entidad de explicabilidad y predicados de agente: +```python +# Explainability entity types (used by both GraphRAG and Agent) +TG_QUESTION = TG + "Question" +TG_EXPLORATION = TG + "Exploration" +TG_FOCUS = TG + "Focus" +TG_SYNTHESIS = TG + "Synthesis" +TG_ANALYSIS = TG + "Analysis" +TG_CONCLUSION = TG + "Conclusion" + +# Agent predicates +TG_THOUGHT = TG + "thought" +TG_ACTION = TG + "action" +TG_ARGUMENTS = TG + "arguments" +TG_OBSERVATION = TG + "observation" +TG_ANSWER = TG + "answer" +``` + +## Archivos Modificados + +| Archivo | Cambio | +|------|--------| +| `trustgraph-base/trustgraph/schema/services/agent.py` | Agregar session_id y collection a AgentRequest | +| `trustgraph-base/trustgraph/messaging/translators/agent.py` | Actualizar el traductor para nuevos campos | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | Agregar tipos de entidad, predicados de agente y predicados de Document RAG | +| `trustgraph-base/trustgraph/provenance/triples.py` | Agregar tipos de TG a los constructores de triples de GraphRAG, agregar constructores de triples de Document RAG | +| `trustgraph-base/trustgraph/provenance/uris.py` | Agregar generadores de URI de Document RAG | +| `trustgraph-base/trustgraph/provenance/__init__.py` | Exportar nuevos tipos, predicados y funciones de Document RAG | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | Agregar explain_id y explain_graph a DocumentRagResponse | +| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | Actualizar DocumentRagResponseTranslator para campos de explicabilidad | +| `trustgraph-flow/trustgraph/agent/react/service.py` | Agregar lógica de productor y registro de explicabilidad | +| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | Agregar devolución de llamada de explicabilidad y emitir triples de procedencia | +| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | Agregar productor de explicabilidad y conectar la devolución de llamada | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | Manejar tipos de traza de agente | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | Listar sesiones de agente junto con GraphRAG | + +## Archivos Creados + +| Archivo | Propósito | +|------|---------| +| `trustgraph-base/trustgraph/provenance/agent.py` | Generadores de triples específicos del agente | + +## Actualizaciones de la CLI + +**Detección:** Tanto GraphRAG como las Preguntas del Agente tienen el tipo `tg:Question`. Se distinguen por: +1. Patrón de URI: `urn:trustgraph:agent:` vs `urn:trustgraph:question:` +2. Entidades derivadas: `tg:Analysis` (agente) vs `tg:Exploration` (GraphRAG) + +**`list_explain_traces.py`:** +- Muestra la columna Tipo (Agente vs GraphRAG) + +**`show_explain_trace.py`:** +- Detecta automáticamente el tipo de traza +- La representación del agente muestra: Pregunta → Paso(s) de análisis → Conclusión + +## Compatibilidad con versiones anteriores + +- `session_id` por defecto es `""` - las solicitudes antiguas funcionan, pero no tendrán procedencia +- `collection` por defecto es `"default"` - alternativa razonable +- La CLI maneja correctamente ambos tipos de traza + +## Verificación + +```bash +# Run an agent query +tg-invoke-agent -q "What is the capital of France?" + +# List traces (should show agent sessions with Type column) +tg-list-explain-traces -U trustgraph -C default + +# Show agent trace +tg-show-explain-trace "urn:trustgraph:agent:xxx" +``` + +## Trabajo Futuro (No Incluido en esta Solicitud de Incorporación) + +- Dependencias de DAG (cuando el análisis N utiliza resultados de múltiples análisis anteriores) +- Enlace de procedencia específico de la herramienta (KnowledgeQuery → su traza GraphRAG) +- Emisión de procedencia en streaming (emitir a medida que se avanza, no en lote al final) diff --git a/docs/tech-specs/agent-explainability.he.md b/docs/tech-specs/agent-explainability.he.md new file mode 100644 index 00000000..a2068b0e --- /dev/null +++ b/docs/tech-specs/agent-explainability.he.md @@ -0,0 +1,272 @@ +# הסברתיות של סוכן: רישום מקורות + +## סקירה כללית + +הוספת רישום מקורות ללולאת הסוכן של React כך שניתן יהיה לעקוב אחר סשנים של סוכנים ולבצע ניפוי באגים באמצעות אותה תשתית הסברתיות כמו GraphRAG. + +**החלטות עיצוב:** +כתיבה ל-`urn:graph:retrieval` (גרף הסברתיות גנרי) +שרשרת תלות ליניארית כרגע (ניתוח N → נגזר מ → ניתוח N-1) +כלים הם תיבות שחורות (רישום קלט/פלט בלבד) +תמיכה ב-DAG (גרף מכוון) נדחית למהלך עתידי + +## סוגי ישויות + +גם GraphRAG וגם Agent משתמשים ב-PROV-O כאונטולוגיה בסיסית עם תת-סוגים ספציפיים ל-TrustGraph: + +### סוגי GraphRAG +| ישות | סוג PROV-O | סוגי TG | תיאור | +|--------|-------------|----------|-------------| +| שאלה | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | השאלה של המשתמש | +| חקירה | `prov:Entity` | `tg:Exploration` | צמתים שאוחזרו מגרף ידע | +| מיקוד | `prov:Entity` | `tg:Focus` | צמתים שנבחרו עם נימוק | +| סינתזה | `prov:Entity` | `tg:Synthesis` | תשובה סופית | + +### סוגי סוכן +| ישות | סוג PROV-O | סוגי TG | תיאור | +|--------|-------------|----------|-------------| +| שאלה | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | השאלה של המשתמש | +| ניתוח | `prov:Entity` | `tg:Analysis` | כל מחזור חשיבה/פעולה/תצפית | +| מסקנה | `prov:Entity` | `tg:Conclusion` | תשובה סופית | + +### סוגי RAG של מסמכים +| ישות | סוג PROV-O | סוגי TG | תיאור | +|--------|-------------|----------|-------------| +| שאלה | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | השאלה של המשתמש | +| חקירה | `prov:Entity` | `tg:Exploration` | חלקים שאוחזרו מחנות מסמכים | +| סינתזה | `prov:Entity` | `tg:Synthesis` | תשובה סופית | + +**הערה:** RAG של מסמכים משתמש בתת-קבוצה של סוגים של GraphRAG (אין שלב מיקוד מכיוון שאין שלב בחירת/נימוק צמתים). + +### תת-סוגים של שאלה + +כל ישויות השאלה חולקות את `tg:Question` כסוג בסיסי אך יש להן תת-סוג ספציפי כדי לזהות את מנגנון השליפה: + +| תת-סוג | תבנית URI | מנגנון | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | RAG של גרף ידע | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | RAG של מסמכים/חלקים | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | סוכן ReAct | + +זה מאפשר שאילתא של כל השאלות באמצעות `tg:Question` תוך סינון לפי מנגנון ספציפי באמצעות תת-הסוג. + +## מודל מקורות + +``` +Question (urn:trustgraph:agent:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasDerivedFrom + │ +Analysis1 (urn:trustgraph:agent:{uuid}/i1) + │ + │ tg:thought = "I need to query the knowledge base..." + │ tg:action = "knowledge-query" + │ tg:arguments = {"question": "..."} + │ tg:observation = "Result from tool..." + │ rdf:type = prov:Entity, tg:Analysis + │ + ↓ prov:wasDerivedFrom + │ +Analysis2 (urn:trustgraph:agent:{uuid}/i2) + │ ... + ↓ prov:wasDerivedFrom + │ +Conclusion (urn:trustgraph:agent:{uuid}/final) + │ + │ tg:answer = "The final response..." + │ rdf:type = prov:Entity, tg:Conclusion +``` + +### מודל מקור (Provenance) של מסמכים בשיטת RAG + +``` +Question (urn:trustgraph:docrag:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasGeneratedBy + │ +Exploration (urn:trustgraph:docrag:{uuid}/exploration) + │ + │ tg:chunkCount = 5 + │ tg:selectedChunk = "chunk-id-1" + │ tg:selectedChunk = "chunk-id-2" + │ ... + │ rdf:type = prov:Entity, tg:Exploration + │ + ↓ prov:wasDerivedFrom + │ +Synthesis (urn:trustgraph:docrag:{uuid}/synthesis) + │ + │ tg:content = "The synthesized answer..." + │ rdf:type = prov:Entity, tg:Synthesis +``` + +## שינויים נדרשים + +### 1. שינויים בסכימה + +**קובץ:** `trustgraph-base/trustgraph/schema/services/agent.py` + +הוסף את השדות `session_id` ו-`collection` ל-`AgentRequest`: +```python +@dataclass +class AgentRequest: + question: str = "" + state: str = "" + group: list[str] | None = None + history: list[AgentStep] = field(default_factory=list) + user: str = "" + collection: str = "default" # NEW: Collection for provenance traces + streaming: bool = False + session_id: str = "" # NEW: For provenance tracking across iterations +``` + +**קובץ:** `trustgraph-base/trustgraph/messaging/translators/agent.py` + +עדכון המתרגם כדי לטפל ב-`session_id` וב-`collection` הן ב-`to_pulsar()` והן ב-`from_pulsar()`. + +### 2. הוספת יצרן הסברות לשירות הסוכנים + +**קובץ:** `trustgraph-flow/trustgraph/agent/react/service.py` + +רישום יצרן "הסברות" (באותו דפוס כמו GraphRAG): +```python +from ... base import ProducerSpec +from ... schema import Triples + +# In __init__: +self.register_specification( + ProducerSpec( + name = "explainability", + schema = Triples, + ) +) +``` + +### 3. יצירת משולש מוצא + +**קובץ:** `trustgraph-base/trustgraph/provenance/agent.py` + +צור פונקציות עזר (בדומה ל-`question_triples`, `exploration_triples` וכו' של GraphRAG): +```python +def agent_session_triples(session_uri, query, timestamp): + """Generate triples for agent Question.""" + return [ + Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY), + Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION), + Triple(s=session_uri, p=TG_QUERY, o=query), + Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp), + ] + +def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation): + """Generate triples for one Analysis step.""" + return [ + Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS), + Triple(s=iteration_uri, p=TG_THOUGHT, o=thought), + Triple(s=iteration_uri, p=TG_ACTION, o=action), + Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)), + Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation), + Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] + +def agent_final_triples(final_uri, parent_uri, answer): + """Generate triples for Conclusion.""" + return [ + Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION), + Triple(s=final_uri, p=TG_ANSWER, o=answer), + Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] +``` + +### 4. הגדרות סוג + +**קובץ:** `trustgraph-base/trustgraph/provenance/namespaces.py` + +הוסף סוגי ישויות הסבר ופרדיקטים של סוכנים: +```python +# Explainability entity types (used by both GraphRAG and Agent) +TG_QUESTION = TG + "Question" +TG_EXPLORATION = TG + "Exploration" +TG_FOCUS = TG + "Focus" +TG_SYNTHESIS = TG + "Synthesis" +TG_ANALYSIS = TG + "Analysis" +TG_CONCLUSION = TG + "Conclusion" + +# Agent predicates +TG_THOUGHT = TG + "thought" +TG_ACTION = TG + "action" +TG_ARGUMENTS = TG + "arguments" +TG_OBSERVATION = TG + "observation" +TG_ANSWER = TG + "answer" +``` + +## קבצים ששונו + +| קובץ | שינוי | +|------|--------| +| `trustgraph-base/trustgraph/schema/services/agent.py` | הוספת session_id ו-collection ל-AgentRequest | +| `trustgraph-base/trustgraph/messaging/translators/agent.py` | עדכון מתרגם עבור שדות חדשים | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | הוספת סוגי ישויות, טענות של סוכן וטענות של Document RAG | +| `trustgraph-base/trustgraph/provenance/triples.py` | הוספת סוגי TG לבונים של משולשים של GraphRAG, הוספת בונים של משולשים של Document RAG | +| `trustgraph-base/trustgraph/provenance/uris.py` | הוספת יוצרי URI של Document RAG | +| `trustgraph-base/trustgraph/provenance/__init__.py` | ייצוא סוגים, טענות ופונקציות חדשות של Document RAG | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | הוספת explain_id ו-explain_graph ל-DocumentRagResponse | +| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | עדכון DocumentRagResponseTranslator עבור שדות הסברתיות | +| `trustgraph-flow/trustgraph/agent/react/service.py` | הוספת מפיק הסברתיות + לוגיקת הקלטה | +| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | הוספת קריאה חוזרת של הסברתיות ופליטת משולשים של מקור | +| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | הוספת מפיק הסברתיות וחיבור הקריאה החוזרת | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | טיפול בסוגי מעקב של סוכן | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | הצגת סשנים של סוכן לצד GraphRAG | + +## קבצים שנוצרו + +| קובץ | מטרה | +|------|---------| +| `trustgraph-base/trustgraph/provenance/agent.py` | יוצרי משולשים ספציפיים לסוכן | + +## עדכוני CLI + +**זיהוי:** גם לשאלות GraphRAG וגם לשאלות סוכן יש סוג `tg:Question`. מובחנים על ידי: +1. תבנית URI: `urn:trustgraph:agent:` לעומת `urn:trustgraph:question:` +2. ישויות נגזרות: `tg:Analysis` (סוכן) לעומת `tg:Exploration` (GraphRAG) + +**`list_explain_traces.py`:** +מציג את עמודת הסוג (סוכן לעומת GraphRAG) + +**`show_explain_trace.py`:** +מזהה אוטומטית את סוג המעקב +הצגת סוכן מציגה: שאלה → שלב(ים) של ניתוח → מסקנה + +## תאימות לאחור + +`session_id` כברירת מחדל הוא `""` - בקשות ישנות עובדות, פשוט לא יהיו להן נתונים של מקור +`collection` כברירת מחדל הוא `"default"` - חזרה סבירה +ה-CLI מטפל בצורה חלקה בשני סוגי המעקב + +## אימות + +```bash +# Run an agent query +tg-invoke-agent -q "What is the capital of France?" + +# List traces (should show agent sessions with Type column) +tg-list-explain-traces -U trustgraph -C default + +# Show agent trace +tg-show-explain-trace "urn:trustgraph:agent:xxx" +``` + +## עבודה עתידית (לא בבקשה הזו) + +תלותיות DAG (כאשר ניתוח N משתמש בתוצאות ממספר ניתוחים קודמים) +קישור מקורות מידע ספציפי לכלי (KnowledgeQuery → המעקב GraphRAG שלו) +פליטת מקורות מידע בסטרימינג (לשלוח תוך כדי פעולה, ולא במקשה בסוף) diff --git a/docs/tech-specs/agent-explainability.hi.md b/docs/tech-specs/agent-explainability.hi.md new file mode 100644 index 00000000..bddfcb56 --- /dev/null +++ b/docs/tech-specs/agent-explainability.hi.md @@ -0,0 +1,272 @@ +# एजेंट स्पष्टता: उत्पत्ति रिकॉर्डिंग + +## अवलोकन + +रिएक्ट एजेंट लूप में उत्पत्ति रिकॉर्डिंग जोड़ें ताकि एजेंट सत्रों को ट्रैक और डीबग किया जा सके, जो कि ग्राफआरएजी के समान स्पष्टता बुनियादी ढांचे का उपयोग करके किया जा सके। + +**डिजाइन निर्णय:** +`urn:graph:retrieval` (सामान्य स्पष्टता ग्राफ) में लिखें +फिलहाल रैखिक निर्भरता श्रृंखला (विश्लेषण N → wasDerivedFrom → विश्लेषण N-1) +उपकरण अपार ब्लैक बॉक्स हैं (केवल इनपुट/आउटपुट रिकॉर्ड करें) +डीएजी समर्थन भविष्य के पुनरावृत्ति के लिए स्थगित है + +## इकाई प्रकार + +ग्राफआरएजी और एजेंट दोनों ही ट्रस्टग्राफ-विशिष्ट उपप्रकारों के साथ पीआरओवी-ओ को आधार ऑन्टोलॉजी के रूप में उपयोग करते हैं: + +### ग्राफआरएजी प्रकार +| इकाई | पीआरओवी-ओ प्रकार | टीजी प्रकार | विवरण | +|--------|-------------|----------|-------------| +| प्रश्न | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | उपयोगकर्ता का प्रश्न | +| अन्वेषण | `prov:Entity` | `tg:Exploration` | ज्ञान ग्राफ से प्राप्त किनारे | +| फोकस | `prov:Entity` | `tg:Focus` | तर्क के साथ चयनित किनारे | +| संश्लेषण | `prov:Entity` | `tg:Synthesis` | अंतिम उत्तर | + +### एजेंट प्रकार +| इकाई | पीआरओवी-ओ प्रकार | टीजी प्रकार | विवरण | +|--------|-------------|----------|-------------| +| प्रश्न | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | उपयोगकर्ता का प्रश्न | +| विश्लेषण | `prov:Entity` | `tg:Analysis` | प्रत्येक सोच/कार्य/अवलोकन चक्र | +| निष्कर्ष | `prov:Entity` | `tg:Conclusion` | अंतिम उत्तर | + +### दस्तावेज़ आरएजी प्रकार +| इकाई | पीआरओवी-ओ प्रकार | टीजी प्रकार | विवरण | +|--------|-------------|----------|-------------| +| प्रश्न | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | उपयोगकर्ता का प्रश्न | +| अन्वेषण | `prov:Entity` | `tg:Exploration` | दस्तावेज़ भंडार से प्राप्त टुकड़े | +| संश्लेषण | `prov:Entity` | `tg:Synthesis` | अंतिम उत्तर | + +**ध्यान दें:** दस्तावेज़ आरएजी ग्राफआरएजी के प्रकारों का एक उपसमुच्चय का उपयोग करता है (कोई फोकस चरण नहीं है क्योंकि कोई किनारा चयन/तर्क चरण नहीं है)। + +### प्रश्न उपप्रकार + +सभी प्रश्न इकाइयों में `tg:Question` को एक आधार प्रकार के रूप में साझा किया जाता है, लेकिन पुनर्प्राप्ति तंत्र की पहचान करने के लिए एक विशिष्ट उपप्रकार होता है: + +| उपप्रकार | यूआरआई पैटर्न | तंत्र | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | ज्ञान ग्राफ आरएजी | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | दस्तावेज़/टुकड़ा आरएजी | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | रीएक्ट एजेंट | + +यह सभी प्रश्नों को `tg:Question` के माध्यम से क्वेरी करने की अनुमति देता है, जबकि उपप्रकार के माध्यम से विशिष्ट तंत्र द्वारा फ़िल्टर किया जा सकता है। + +## उत्पत्ति मॉडल + +``` +Question (urn:trustgraph:agent:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasDerivedFrom + │ +Analysis1 (urn:trustgraph:agent:{uuid}/i1) + │ + │ tg:thought = "I need to query the knowledge base..." + │ tg:action = "knowledge-query" + │ tg:arguments = {"question": "..."} + │ tg:observation = "Result from tool..." + │ rdf:type = prov:Entity, tg:Analysis + │ + ↓ prov:wasDerivedFrom + │ +Analysis2 (urn:trustgraph:agent:{uuid}/i2) + │ ... + ↓ prov:wasDerivedFrom + │ +Conclusion (urn:trustgraph:agent:{uuid}/final) + │ + │ tg:answer = "The final response..." + │ rdf:type = prov:Entity, tg:Conclusion +``` + +### दस्तावेज़ आरएजी उत्पत्ति मॉडल + +``` +Question (urn:trustgraph:docrag:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasGeneratedBy + │ +Exploration (urn:trustgraph:docrag:{uuid}/exploration) + │ + │ tg:chunkCount = 5 + │ tg:selectedChunk = "chunk-id-1" + │ tg:selectedChunk = "chunk-id-2" + │ ... + │ rdf:type = prov:Entity, tg:Exploration + │ + ↓ prov:wasDerivedFrom + │ +Synthesis (urn:trustgraph:docrag:{uuid}/synthesis) + │ + │ tg:content = "The synthesized answer..." + │ rdf:type = prov:Entity, tg:Synthesis +``` + +## आवश्यक परिवर्तन + +### 1. स्कीमा परिवर्तन + +**फ़ाइल:** `trustgraph-base/trustgraph/schema/services/agent.py` + +`AgentRequest` में `session_id` और `collection` फ़ील्ड जोड़ें: +```python +@dataclass +class AgentRequest: + question: str = "" + state: str = "" + group: list[str] | None = None + history: list[AgentStep] = field(default_factory=list) + user: str = "" + collection: str = "default" # NEW: Collection for provenance traces + streaming: bool = False + session_id: str = "" # NEW: For provenance tracking across iterations +``` + +**फ़ाइल:** `trustgraph-base/trustgraph/messaging/translators/agent.py` + +अनुवादक को `session_id` और `collection` को `to_pulsar()` और `from_pulsar()` दोनों में संभालने के लिए अपडेट करें। + +### 2. एजेंट सेवा में "एक्सप्लेनेबिलिटी" उत्पादक जोड़ें + +**फ़ाइल:** `trustgraph-flow/trustgraph/agent/react/service.py` + +एक "एक्सप्लेनेबिलिटी" उत्पादक को पंजीकृत करें (ग्राफआरएजी के समान पैटर्न): +```python +from ... base import ProducerSpec +from ... schema import Triples + +# In __init__: +self.register_specification( + ProducerSpec( + name = "explainability", + schema = Triples, + ) +) +``` + +### 3. उत्पत्ति त्रिक निर्माण + +**फ़ाइल:** `trustgraph-base/trustgraph/provenance/agent.py` + +सहायक फ़ंक्शन बनाएँ (ग्राफ़आरएजी के `question_triples`, `exploration_triples`, आदि के समान): +```python +def agent_session_triples(session_uri, query, timestamp): + """Generate triples for agent Question.""" + return [ + Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY), + Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION), + Triple(s=session_uri, p=TG_QUERY, o=query), + Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp), + ] + +def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation): + """Generate triples for one Analysis step.""" + return [ + Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS), + Triple(s=iteration_uri, p=TG_THOUGHT, o=thought), + Triple(s=iteration_uri, p=TG_ACTION, o=action), + Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)), + Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation), + Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] + +def agent_final_triples(final_uri, parent_uri, answer): + """Generate triples for Conclusion.""" + return [ + Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION), + Triple(s=final_uri, p=TG_ANSWER, o=answer), + Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] +``` + +### 4. प्रकार की परिभाषाएँ + +**फ़ाइल:** `trustgraph-base/trustgraph/provenance/namespaces.py` + +व्याख्यात्मकता इकाई प्रकार और एजेंट विधेयकों को जोड़ें: +```python +# Explainability entity types (used by both GraphRAG and Agent) +TG_QUESTION = TG + "Question" +TG_EXPLORATION = TG + "Exploration" +TG_FOCUS = TG + "Focus" +TG_SYNTHESIS = TG + "Synthesis" +TG_ANALYSIS = TG + "Analysis" +TG_CONCLUSION = TG + "Conclusion" + +# Agent predicates +TG_THOUGHT = TG + "thought" +TG_ACTION = TG + "action" +TG_ARGUMENTS = TG + "arguments" +TG_OBSERVATION = TG + "observation" +TG_ANSWER = TG + "answer" +``` + +## संशोधित फ़ाइलें + +| फ़ाइल | परिवर्तन | +|------|--------| +| `trustgraph-base/trustgraph/schema/services/agent.py` | AgentRequest में session_id और collection जोड़ें | +| `trustgraph-base/trustgraph/messaging/translators/agent.py` | नए फ़ील्ड के लिए ट्रांसलेटर को अपडेट करें | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | एंटिटी प्रकार, एजेंट प्रेडिकेट और Document RAG प्रेडिकेट जोड़ें | +| `trustgraph-base/trustgraph/provenance/triples.py` | GraphRAG ट्रिपल बिल्डरों में TG प्रकार जोड़ें, Document RAG ट्रिपल बिल्डर जोड़ें | +| `trustgraph-base/trustgraph/provenance/uris.py` | Document RAG URI जनरेटर जोड़ें | +| `trustgraph-base/trustgraph/provenance/__init__.py` | नए प्रकार, प्रेडिकेट और Document RAG फ़ंक्शन निर्यात करें | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | DocumentRagResponse में explain_id और explain_graph जोड़ें | +| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | व्याख्यात्मक फ़ील्ड के लिए DocumentRagResponseTranslator को अपडेट करें | +| `trustgraph-flow/trustgraph/agent/react/service.py` | व्याख्यात्मक उत्पादक + रिकॉर्डिंग लॉजिक जोड़ें | +| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | व्याख्यात्मक कॉलबैक जोड़ें और प्रोवेनेंस ट्रिपल उत्सर्जित करें | +| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | व्याख्यात्मक उत्पादक जोड़ें और कॉलबैक को कनेक्ट करें | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | एजेंट ट्रेस प्रकारों को संभालें | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | GraphRAG के साथ एजेंट सत्रों को सूचीबद्ध करें | + +## बनाई गई फ़ाइलें + +| फ़ाइल | उद्देश्य | +|------|---------| +| `trustgraph-base/trustgraph/provenance/agent.py` | एजेंट-विशिष्ट ट्रिपल जनरेटर | + +## CLI अपडेट + +**पहचान:** GraphRAG और Agent Questions दोनों में `tg:Question` प्रकार होता है। निम्नलिखित द्वारा पहचाना जाता है: +1. URI पैटर्न: `urn:trustgraph:agent:` बनाम `urn:trustgraph:question:` +2. व्युत्पन्न एंटिटीज: `tg:Analysis` (एजेंट) बनाम `tg:Exploration` (GraphRAG) + +**`list_explain_traces.py`:** +टाइप कॉलम दिखाता है (एजेंट बनाम GraphRAG) + +**`show_explain_trace.py`:** +स्वचालित रूप से ट्रेस प्रकार का पता लगाता है +एजेंट रेंडरिंग दिखाता है: प्रश्न → विश्लेषण चरण(s) → निष्कर्ष + +## पिछली अनुकूलता + +`session_id` डिफ़ॉल्ट रूप से `""` होता है - पुराने अनुरोध काम करते हैं, लेकिन उनमें प्रोवेनेंस नहीं होगा +`collection` डिफ़ॉल्ट रूप से `"default"` होता है - उचित बैकअप +CLI दोनों ट्रेस प्रकारों को आसानी से संभालता है + +## सत्यापन + +```bash +# Run an agent query +tg-invoke-agent -q "What is the capital of France?" + +# List traces (should show agent sessions with Type column) +tg-list-explain-traces -U trustgraph -C default + +# Show agent trace +tg-show-explain-trace "urn:trustgraph:agent:xxx" +``` + +## भविष्य की योजनाएं (इस पुल अनुरोध में नहीं) + +डीएजी निर्भरताएँ (जब विश्लेषण एन, पिछले कई विश्लेषणों के परिणामों का उपयोग करता है) +टूल-विशिष्ट उत्पत्ति लिंकिंग (नॉलेजक्वेरी → इसका ग्राफआरएजी ट्रेस) +स्ट्रीमिंग उत्पत्ति उत्सर्जन (जैसे-जैसे उत्पन्न होता है, अंत में बैच न करें) diff --git a/docs/tech-specs/agent-explainability.pt.md b/docs/tech-specs/agent-explainability.pt.md new file mode 100644 index 00000000..aa8e0c9c --- /dev/null +++ b/docs/tech-specs/agent-explainability.pt.md @@ -0,0 +1,272 @@ +# Explicabilidade do Agente: Registro de Proveniência + +## Visão Geral + +Adicionar o registro de proveniência ao loop do agente React para que as sessões do agente possam ser rastreadas e depuradas usando a mesma infraestrutura de explicabilidade do GraphRAG. + +**Decisões de Design:** +- Escrever em `urn:graph:retrieval` (grafo de explicabilidade genérico) +- Cadeia de dependência linear por enquanto (análise N → foiDerivadoDe → análise N-1) +- As ferramentas são caixas pretas (registrar apenas entrada/saída) +- Suporte a DAG (Directed Acyclic Graph - Grafo Acíclico Direcionado) adiado para uma iteração futura + +## Tipos de Entidade + +Tanto o GraphRAG quanto o Agent usam PROV-O como a ontologia base, com subtipos específicos do TrustGraph: + +### Tipos do GraphRAG +| Entidade | Tipo PROV-O | Tipos TG | Descrição | +|--------|-------------|----------|-------------| +| Pergunta | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | A consulta do usuário | +| Exploração | `prov:Entity` | `tg:Exploration` | Arestas recuperadas do grafo de conhecimento | +| Foco | `prov:Entity` | `tg:Focus` | Arestas selecionadas com raciocínio | +| Síntese | `prov:Entity` | `tg:Synthesis` | Resposta final | + +### Tipos do Agente +| Entidade | Tipo PROV-O | Tipos TG | Descrição | +|--------|-------------|----------|-------------| +| Pergunta | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | A consulta do usuário | +| Análise | `prov:Entity` | `tg:Analysis` | Cada ciclo de pensar/agir/observar | +| Conclusão | `prov:Entity` | `tg:Conclusion` | Resposta final | + +### Tipos do Document RAG +| Entidade | Tipo PROV-O | Tipos TG | Descrição | +|--------|-------------|----------|-------------| +| Pergunta | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | A consulta do usuário | +| Exploração | `prov:Entity` | `tg:Exploration` | Trechos recuperados do armazenamento de documentos | +| Síntese | `prov:Entity` | `tg:Synthesis` | Resposta final | + +**Observação:** O Document RAG usa um subconjunto dos tipos do GraphRAG (sem a etapa de Foco, pois não há seleção/raciocínio de arestas). + +### Subtipos de Pergunta + +Todas as entidades de Pergunta compartilham `tg:Question` como um tipo base, mas têm um subtipo específico para identificar o mecanismo de recuperação: + +| Subtipo | Padrão URI | Mecanismo | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | RAG de grafo de conhecimento | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | RAG de documento/trecho | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | Agente ReAct | + +Isso permite consultar todas as perguntas via `tg:Question`, filtrando por mecanismo específico através do subtipo. + +## Modelo de Proveniência + +``` +Question (urn:trustgraph:agent:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasDerivedFrom + │ +Analysis1 (urn:trustgraph:agent:{uuid}/i1) + │ + │ tg:thought = "I need to query the knowledge base..." + │ tg:action = "knowledge-query" + │ tg:arguments = {"question": "..."} + │ tg:observation = "Result from tool..." + │ rdf:type = prov:Entity, tg:Analysis + │ + ↓ prov:wasDerivedFrom + │ +Analysis2 (urn:trustgraph:agent:{uuid}/i2) + │ ... + ↓ prov:wasDerivedFrom + │ +Conclusion (urn:trustgraph:agent:{uuid}/final) + │ + │ tg:answer = "The final response..." + │ rdf:type = prov:Entity, tg:Conclusion +``` + +### Modelo de Proveniência de Documentos RAG + +``` +Question (urn:trustgraph:docrag:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasGeneratedBy + │ +Exploration (urn:trustgraph:docrag:{uuid}/exploration) + │ + │ tg:chunkCount = 5 + │ tg:selectedChunk = "chunk-id-1" + │ tg:selectedChunk = "chunk-id-2" + │ ... + │ rdf:type = prov:Entity, tg:Exploration + │ + ↓ prov:wasDerivedFrom + │ +Synthesis (urn:trustgraph:docrag:{uuid}/synthesis) + │ + │ tg:content = "The synthesized answer..." + │ rdf:type = prov:Entity, tg:Synthesis +``` + +## Alterações Necessárias + +### 1. Alterações no Esquema + +**Arquivo:** `trustgraph-base/trustgraph/schema/services/agent.py` + +Adicionar os campos `session_id` e `collection` a `AgentRequest`: +```python +@dataclass +class AgentRequest: + question: str = "" + state: str = "" + group: list[str] | None = None + history: list[AgentStep] = field(default_factory=list) + user: str = "" + collection: str = "default" # NEW: Collection for provenance traces + streaming: bool = False + session_id: str = "" # NEW: For provenance tracking across iterations +``` + +**Arquivo:** `trustgraph-base/trustgraph/messaging/translators/agent.py` + +Atualizar o tradutor para lidar com `session_id` e `collection` tanto em `to_pulsar()` quanto em `from_pulsar()`. + +### 2. Adicionar Produtor de Explicabilidade ao Serviço de Agente + +**Arquivo:** `trustgraph-flow/trustgraph/agent/react/service.py` + +Registrar um "produtor de explicabilidade" (mesmo padrão do GraphRAG): +```python +from ... base import ProducerSpec +from ... schema import Triples + +# In __init__: +self.register_specification( + ProducerSpec( + name = "explainability", + schema = Triples, + ) +) +``` + +### 3. Geração de Triplas de Proveniência + +**Arquivo:** `trustgraph-base/trustgraph/provenance/agent.py` + +Crie funções auxiliares (semelhantes a `question_triples`, `exploration_triples`, etc. do GraphRAG): +```python +def agent_session_triples(session_uri, query, timestamp): + """Generate triples for agent Question.""" + return [ + Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY), + Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION), + Triple(s=session_uri, p=TG_QUERY, o=query), + Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp), + ] + +def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation): + """Generate triples for one Analysis step.""" + return [ + Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS), + Triple(s=iteration_uri, p=TG_THOUGHT, o=thought), + Triple(s=iteration_uri, p=TG_ACTION, o=action), + Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)), + Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation), + Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] + +def agent_final_triples(final_uri, parent_uri, answer): + """Generate triples for Conclusion.""" + return [ + Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION), + Triple(s=final_uri, p=TG_ANSWER, o=answer), + Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] +``` + +### 4. Definições de Tipo + +**Arquivo:** `trustgraph-base/trustgraph/provenance/namespaces.py` + +Adicionar tipos de entidade de explicabilidade e predicados de agente: +```python +# Explainability entity types (used by both GraphRAG and Agent) +TG_QUESTION = TG + "Question" +TG_EXPLORATION = TG + "Exploration" +TG_FOCUS = TG + "Focus" +TG_SYNTHESIS = TG + "Synthesis" +TG_ANALYSIS = TG + "Analysis" +TG_CONCLUSION = TG + "Conclusion" + +# Agent predicates +TG_THOUGHT = TG + "thought" +TG_ACTION = TG + "action" +TG_ARGUMENTS = TG + "arguments" +TG_OBSERVATION = TG + "observation" +TG_ANSWER = TG + "answer" +``` + +## Arquivos Modificados + +| Arquivo | Alteração | +|------|--------| +| `trustgraph-base/trustgraph/schema/services/agent.py` | Adiciona session_id e collection a AgentRequest | +| `trustgraph-base/trustgraph/messaging/translators/agent.py` | Atualiza o tradutor para novos campos | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | Adiciona tipos de entidade, predicados de agente e predicados Document RAG | +| `trustgraph-base/trustgraph/provenance/triples.py` | Adiciona tipos TG aos construtores de triplas GraphRAG, adiciona construtores de triplas Document RAG | +| `trustgraph-base/trustgraph/provenance/uris.py` | Adiciona geradores de URI Document RAG | +| `trustgraph-base/trustgraph/provenance/__init__.py` | Exporta novos tipos, predicados e funções Document RAG | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | Adiciona explain_id e explain_graph a DocumentRagResponse | +| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | Atualiza DocumentRagResponseTranslator para campos de explicabilidade | +| `trustgraph-flow/trustgraph/agent/react/service.py` | Adiciona lógica de produção e gravação de explicabilidade | +| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | Adiciona callback de explicabilidade e emite triplas de procedência | +| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | Adiciona produtor de explicabilidade e conecta o callback | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | Lida com tipos de rastreamento de agente | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | Lista sessões de agente junto com GraphRAG | + +## Arquivos Criados + +| Arquivo | Propósito | +|------|---------| +| `trustgraph-base/trustgraph/provenance/agent.py` | Geradores de triplas específicos para agente | + +## Atualizações da CLI + +**Detecção:** Tanto GraphRAG quanto Agent Questions têm o tipo `tg:Question`. Distinguido por: +1. Padrão de URI: `urn:trustgraph:agent:` vs `urn:trustgraph:question:` +2. Entidades derivadas: `tg:Analysis` (agente) vs `tg:Exploration` (GraphRAG) + +**`list_explain_traces.py`:** +- Mostra a coluna Tipo (Agente vs GraphRAG) + +**`show_explain_trace.py`:** +- Detecta automaticamente o tipo de rastreamento +- A renderização do agente mostra: Pergunta → Etapa(s) de análise → Conclusão + +## Compatibilidade com versões anteriores + +- `session_id` padrão é `""` - solicitações antigas funcionam, mas não terão procedência +- `collection` padrão é `"default"` - fallback razoável +- A CLI lida graciosamente com ambos os tipos de rastreamento + +## Verificação + +```bash +# Run an agent query +tg-invoke-agent -q "What is the capital of France?" + +# List traces (should show agent sessions with Type column) +tg-list-explain-traces -U trustgraph -C default + +# Show agent trace +tg-show-explain-trace "urn:trustgraph:agent:xxx" +``` + +## Trabalhos Futuros (Não Neste PR) + +- Dependências de DAG (quando a análise N usa resultados de várias análises anteriores) +- Vinculação de rastreabilidade específica da ferramenta (KnowledgeQuery → seu rastreamento GraphRAG) +- Emissão de rastreabilidade em fluxo (emitir continuamente, não em lote no final) diff --git a/docs/tech-specs/agent-explainability.ru.md b/docs/tech-specs/agent-explainability.ru.md new file mode 100644 index 00000000..3e49202c --- /dev/null +++ b/docs/tech-specs/agent-explainability.ru.md @@ -0,0 +1,272 @@ +# Объяснимость работы агента: Регистрация происхождения + +## Обзор + +Добавьте регистрацию происхождения в цикл работы агента React, чтобы сеансы работы агента можно было отслеживать и отлаживать с использованием той же инфраструктуры объяснимости, что и в GraphRAG. + +**Принятые решения:** +Запись в `urn:graph:retrieval` (общий граф объяснимости) +Линейная цепочка зависимостей на данный момент (анализ N → был получен из → анализ N-1) +Инструменты являются непрозрачными "черными ящиками" (записывайте только входные и выходные данные) +Поддержка DAG отложена до будущей итерации + +## Типы сущностей + +И GraphRAG, и Agent используют PROV-O в качестве базовой онтологии с подтипами, специфичными для TrustGraph: + +### Типы GraphRAG +| Сущность | Тип PROV-O | Типы TG | Описание | +|--------|-------------|----------|-------------| +| Вопрос | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | Запрос пользователя | +| Исследование | `prov:Entity` | `tg:Exploration` | Ряды, извлеченные из графа знаний | +| Фокус | `prov:Entity` | `tg:Focus` | Выбранные ряды с обоснованием | +| Синтез | `prov:Entity` | `tg:Synthesis` | Окончательный ответ | + +### Типы Agent +| Сущность | Тип PROV-O | Типы TG | Описание | +|--------|-------------|----------|-------------| +| Вопрос | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | Запрос пользователя | +| Анализ | `prov:Entity` | `tg:Analysis` | Каждый цикл "думай/действуй/наблюдай" | +| Вывод | `prov:Entity` | `tg:Conclusion` | Окончательный ответ | + +### Типы Document RAG +| Сущность | Тип PROV-O | Типы TG | Описание | +|--------|-------------|----------|-------------| +| Вопрос | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | Запрос пользователя | +| Исследование | `prov:Entity` | `tg:Exploration` | Части, извлеченные из хранилища документов | +| Синтез | `prov:Entity` | `tg:Synthesis` | Окончательный ответ | + +**Примечание:** Document RAG использует подмножество типов GraphRAG (нет этапа "Фокус", поскольку нет этапа выбора/обоснования ребер). + +### Подтипы вопросов + +Все сущности "Вопрос" имеют `tg:Question` в качестве базового типа, но имеют определенный подтип для идентификации механизма извлечения: + +| Подтип | Шаблон URI | Механизм | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | RAG на основе графа знаний | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | RAG на основе документов/частей | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | Агент ReAct | + +Это позволяет запрашивать все вопросы через `tg:Question`, одновременно фильтруя по конкретному механизму с помощью подтипа. + +## Модель происхождения + +``` +Question (urn:trustgraph:agent:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasDerivedFrom + │ +Analysis1 (urn:trustgraph:agent:{uuid}/i1) + │ + │ tg:thought = "I need to query the knowledge base..." + │ tg:action = "knowledge-query" + │ tg:arguments = {"question": "..."} + │ tg:observation = "Result from tool..." + │ rdf:type = prov:Entity, tg:Analysis + │ + ↓ prov:wasDerivedFrom + │ +Analysis2 (urn:trustgraph:agent:{uuid}/i2) + │ ... + ↓ prov:wasDerivedFrom + │ +Conclusion (urn:trustgraph:agent:{uuid}/final) + │ + │ tg:answer = "The final response..." + │ rdf:type = prov:Entity, tg:Conclusion +``` + +### Модель происхождения документов RAG + +``` +Question (urn:trustgraph:docrag:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasGeneratedBy + │ +Exploration (urn:trustgraph:docrag:{uuid}/exploration) + │ + │ tg:chunkCount = 5 + │ tg:selectedChunk = "chunk-id-1" + │ tg:selectedChunk = "chunk-id-2" + │ ... + │ rdf:type = prov:Entity, tg:Exploration + │ + ↓ prov:wasDerivedFrom + │ +Synthesis (urn:trustgraph:docrag:{uuid}/synthesis) + │ + │ tg:content = "The synthesized answer..." + │ rdf:type = prov:Entity, tg:Synthesis +``` + +## Необходимые изменения + +### 1. Изменения схемы + +**Файл:** `trustgraph-base/trustgraph/schema/services/agent.py` + +Добавить поля `session_id` и `collection` в `AgentRequest`: +```python +@dataclass +class AgentRequest: + question: str = "" + state: str = "" + group: list[str] | None = None + history: list[AgentStep] = field(default_factory=list) + user: str = "" + collection: str = "default" # NEW: Collection for provenance traces + streaming: bool = False + session_id: str = "" # NEW: For provenance tracking across iterations +``` + +**Файл:** `trustgraph-base/trustgraph/messaging/translators/agent.py` + +Обновить переводчик для обработки `session_id` и `collection` как в `to_pulsar()`, так и в `from_pulsar()`. + +### 2. Добавить компонент "Explainability Producer" в сервис Agent + +**Файл:** `trustgraph-flow/trustgraph/agent/react/service.py` + +Зарегистрировать компонент "explainability" (в соответствии с тем же шаблоном, что и GraphRAG): +```python +from ... base import ProducerSpec +from ... schema import Triples + +# In __init__: +self.register_specification( + ProducerSpec( + name = "explainability", + schema = Triples, + ) +) +``` + +### 3. Генерация триплетов происхождения + +**Файл:** `trustgraph-base/trustgraph/provenance/agent.py` + +Создайте вспомогательные функции (подобные `question_triples`, `exploration_triples` и т.д. в GraphRAG): +```python +def agent_session_triples(session_uri, query, timestamp): + """Generate triples for agent Question.""" + return [ + Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY), + Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION), + Triple(s=session_uri, p=TG_QUERY, o=query), + Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp), + ] + +def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation): + """Generate triples for one Analysis step.""" + return [ + Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS), + Triple(s=iteration_uri, p=TG_THOUGHT, o=thought), + Triple(s=iteration_uri, p=TG_ACTION, o=action), + Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)), + Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation), + Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] + +def agent_final_triples(final_uri, parent_uri, answer): + """Generate triples for Conclusion.""" + return [ + Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION), + Triple(s=final_uri, p=TG_ANSWER, o=answer), + Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] +``` + +### 4. Определения типов + +**Файл:** `trustgraph-base/trustgraph/provenance/namespaces.py` + +Добавить типы сущностей, обеспечивающих объяснимость, и предикаты агентов: +```python +# Explainability entity types (used by both GraphRAG and Agent) +TG_QUESTION = TG + "Question" +TG_EXPLORATION = TG + "Exploration" +TG_FOCUS = TG + "Focus" +TG_SYNTHESIS = TG + "Synthesis" +TG_ANALYSIS = TG + "Analysis" +TG_CONCLUSION = TG + "Conclusion" + +# Agent predicates +TG_THOUGHT = TG + "thought" +TG_ACTION = TG + "action" +TG_ARGUMENTS = TG + "arguments" +TG_OBSERVATION = TG + "observation" +TG_ANSWER = TG + "answer" +``` + +## Измененные файлы + +| Файл | Изменение | +|------|--------| +| `trustgraph-base/trustgraph/schema/services/agent.py` | Добавлены session_id и collection в AgentRequest | +| `trustgraph-base/trustgraph/messaging/translators/agent.py` | Обновлен переводчик для новых полей | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | Добавлены типы сущностей, предикаты агента и предикаты Document RAG | +| `trustgraph-base/trustgraph/provenance/triples.py` | Добавлены типы TG для конструкторов троек GraphRAG, добавлены конструкторы троек Document RAG | +| `trustgraph-base/trustgraph/provenance/uris.py` | Добавлены генераторы URI для Document RAG | +| `trustgraph-base/trustgraph/provenance/__init__.py` | Экспортированы новые типы, предикаты и функции Document RAG | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | Добавлены explain_id и explain_graph в DocumentRagResponse | +| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | Обновлен DocumentRagResponseTranslator для полей, связанных с объяснением | +| `trustgraph-flow/trustgraph/agent/react/service.py` | Добавлена логика создания и записи информации о объяснении | +| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | Добавлен колбэк для информации о объяснении и выводятся тройки, содержащие информацию о происхождении | +| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | Добавлен генератор информации о объяснении и подключен колбэк | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | Обработка типов трассировки агента | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | Отображение сессий агента вместе с GraphRAG | + +## Созданные файлы + +| Файл | Назначение | +|------|---------| +| `trustgraph-base/trustgraph/provenance/agent.py` | Генераторы троек, специфичные для агента | + +## Обновления CLI + +**Обнаружение:** И GraphRAG, и вопросы агента имеют тип `tg:Question`. Отличаются следующим: +1. Шаблон URI: `urn:trustgraph:agent:` против `urn:trustgraph:question:` +2. Выводимые сущности: `tg:Analysis` (агент) против `tg:Exploration` (GraphRAG) + +**`list_explain_traces.py`:** +Отображает столбец "Тип" (Агент против GraphRAG) + +**`show_explain_trace.py`:** +Автоматически определяет тип трассировки +Отображение информации об агенте: Вопрос → Шаги анализа → Вывод + +## Обратная совместимость + +`session_id` по умолчанию равно `""` - старые запросы работают, но не будут содержать информацию о происхождении +`collection` по умолчанию равно `"default"` - разумная альтернатива +CLI корректно обрабатывает оба типа трассировки + +## Проверка + +```bash +# Run an agent query +tg-invoke-agent -q "What is the capital of France?" + +# List traces (should show agent sessions with Type column) +tg-list-explain-traces -U trustgraph -C default + +# Show agent trace +tg-show-explain-trace "urn:trustgraph:agent:xxx" +``` + +## Будущие задачи (не входят в этот PR) + +Зависимости DAG (когда анализ N использует результаты нескольких предыдущих анализов) +Связь с конкретными инструментами (KnowledgeQuery → его трассировка GraphRAG) +Потоковая передача метаданных (отправлять по мере выполнения, а не пакетами в конце) diff --git a/docs/tech-specs/agent-explainability.sw.md b/docs/tech-specs/agent-explainability.sw.md new file mode 100644 index 00000000..5f7cae25 --- /dev/null +++ b/docs/tech-specs/agent-explainability.sw.md @@ -0,0 +1,272 @@ +# Ufafanuzi wa Mwakala: Urekodaji wa Asili + +## Muhtasari + +Ongeza urekodaji wa asili kwenye mzunguko wa wakala wa React ili vipindi vya wakala viweze kufuatiliwa na kurekebishwa kwa kutumia miundomino sawa ya ufafanuzi kama GraphRAG. + +**Maamuzi ya Ubunifu:** +- Andika kwenye `urn:graph:retrieval` (picha ya ufafanuzi ya jumla) +- Mnyororo wa utegemezi wa mstari kwa sasa (uchambuzi N → ilitokana na → uchambuzi N-1) +- Zana ni masanduku meusi (rekodi tu ingizo/patto) +- Usaidizi wa DAG umeahirishwa hadi toleo la baadaye + +## Aina za Vitambulisho + +GraphRAG na Agent hutumia PROV-O kama ontolojia ya msingi na aina za ziada maalum za TrustGraph: + +### Aina za GraphRAG +| Vitambulisho | Aina ya PROV-O | Aina za TG | Maelezo | +|--------|-------------|----------|-------------| +| Swali | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | Uliza wa mtumiaji | +| Uchunguzi | `prov:Entity` | `tg:Exploration` | Edges iliyopatikana kutoka kwenye grafu ya maarifa | +| Lengo | `prov:Entity` | `tg:Focus` | Edges iliyochaguliwa na hoja | +| Muunganisho | `prov:Entity` | `tg:Synthesis` | Jibu la mwisho | + +### Aina za Wakala +| Vitambulisho | Aina ya PROV-O | Aina za TG | Maelezo | +|--------|-------------|----------|-------------| +| Swali | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | Uliza wa mtumiaji | +| Uchambuzi | `prov:Entity` | `tg:Analysis` | Kila mzunguko wa kufikiria/kutenda/kuona | +| Hitimisho | `prov:Entity` | `tg:Conclusion` | Jibu la mwisho | + +### Aina za RAG za Hati +| Vitambulisho | Aina ya PROV-O | Aina za TG | Maelezo | +|--------|-------------|----------|-------------| +| Swali | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | Uliza wa mtumiaji | +| Uchunguzi | `prov:Entity` | `tg:Exploration` | Sehemu zilizopatikana kutoka kwenye duka la hati | +| Muunganisho | `prov:Entity` | `tg:Synthesis` | Jibu la mwisho | + +**Kumbuka:** RAG ya Hati hutumia sehemu ya aina za GraphRAG (hakuna hatua ya Lengo kwa sababu hakuna awamu ya uteuzi/hoja ya edge). + +### Aina za Ndogo za Swali + +Aina zote za Swali hushiriki `tg:Question` kama aina ya msingi lakini zina aina maalum ili kutambua utaratibu wa urejesho: + +| Aina | Mfumo wa URI | Utaratibu | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | RAG ya grafu ya maarifa | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | RAG ya hati/sehemu | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | Wakala wa ReAct | + +Hii inaruhusu kuuliza maswali yote kupitia `tg:Question` huku ikiwezesha kuchujwa kwa utaratibu maalum kupitia aina. + +## Mfumo wa Asili + +``` +Question (urn:trustgraph:agent:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasDerivedFrom + │ +Analysis1 (urn:trustgraph:agent:{uuid}/i1) + │ + │ tg:thought = "I need to query the knowledge base..." + │ tg:action = "knowledge-query" + │ tg:arguments = {"question": "..."} + │ tg:observation = "Result from tool..." + │ rdf:type = prov:Entity, tg:Analysis + │ + ↓ prov:wasDerivedFrom + │ +Analysis2 (urn:trustgraph:agent:{uuid}/i2) + │ ... + ↓ prov:wasDerivedFrom + │ +Conclusion (urn:trustgraph:agent:{uuid}/final) + │ + │ tg:answer = "The final response..." + │ rdf:type = prov:Entity, tg:Conclusion +``` + +### Mfumo wa Asili ya Hati ya RAG + +``` +Question (urn:trustgraph:docrag:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasGeneratedBy + │ +Exploration (urn:trustgraph:docrag:{uuid}/exploration) + │ + │ tg:chunkCount = 5 + │ tg:selectedChunk = "chunk-id-1" + │ tg:selectedChunk = "chunk-id-2" + │ ... + │ rdf:type = prov:Entity, tg:Exploration + │ + ↓ prov:wasDerivedFrom + │ +Synthesis (urn:trustgraph:docrag:{uuid}/synthesis) + │ + │ tg:content = "The synthesized answer..." + │ rdf:type = prov:Entity, tg:Synthesis +``` + +## Mabadiliko Yanayohitajika + +### 1. Mabadiliko ya Muundo + +**Faili:** `trustgraph-base/trustgraph/schema/services/agent.py` + +Ongeza sehemu za `session_id` na `collection` kwenye `AgentRequest`: +```python +@dataclass +class AgentRequest: + question: str = "" + state: str = "" + group: list[str] | None = None + history: list[AgentStep] = field(default_factory=list) + user: str = "" + collection: str = "default" # NEW: Collection for provenance traces + streaming: bool = False + session_id: str = "" # NEW: For provenance tracking across iterations +``` + +**Faidio:** `trustgraph-base/trustgraph/messaging/translators/agent.py` + +Sasisha mtafsiri ili kushughulikia `session_id` na `collection` katika `to_pulsar()` na `from_pulsar()`. + +### 2. Ongeza Mzalishaji wa Ufafanuzi kwa Huduma ya Wakala + +**Faidio:** `trustgraph-flow/trustgraph/agent/react/service.py` + +Sajili "mzalishaji wa ufafanuzi" (mfumo sawa na GraphRAG): +```python +from ... base import ProducerSpec +from ... schema import Triples + +# In __init__: +self.register_specification( + ProducerSpec( + name = "explainability", + schema = Triples, + ) +) +``` + +### 3. Uzalishaji wa Mfumo wa Asili + +**Faili:** `trustgraph-base/trustgraph/provenance/agent.py` + +Unda kazi za msaada (kama zile za GraphRAG, kama `question_triples`, `exploration_triples`, n.k.): +```python +def agent_session_triples(session_uri, query, timestamp): + """Generate triples for agent Question.""" + return [ + Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY), + Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION), + Triple(s=session_uri, p=TG_QUERY, o=query), + Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp), + ] + +def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation): + """Generate triples for one Analysis step.""" + return [ + Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS), + Triple(s=iteration_uri, p=TG_THOUGHT, o=thought), + Triple(s=iteration_uri, p=TG_ACTION, o=action), + Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)), + Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation), + Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] + +def agent_final_triples(final_uri, parent_uri, answer): + """Generate triples for Conclusion.""" + return [ + Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION), + Triple(s=final_uri, p=TG_ANSWER, o=answer), + Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] +``` + +### 4. Ufafanuzi wa Aina + +**Faili:** `trustgraph-base/trustgraph/provenance/namespaces.py` + +Ongeza aina za vitu vya uelewaji na sentensi za wakala: +```python +# Explainability entity types (used by both GraphRAG and Agent) +TG_QUESTION = TG + "Question" +TG_EXPLORATION = TG + "Exploration" +TG_FOCUS = TG + "Focus" +TG_SYNTHESIS = TG + "Synthesis" +TG_ANALYSIS = TG + "Analysis" +TG_CONCLUSION = TG + "Conclusion" + +# Agent predicates +TG_THOUGHT = TG + "thought" +TG_ACTION = TG + "action" +TG_ARGUMENTS = TG + "arguments" +TG_OBSERVATION = TG + "observation" +TG_ANSWER = TG + "answer" +``` + +## Faili Yaliyobadilishwa + +| Faili | Mabadiliko | +|------|--------| +| `trustgraph-base/trustgraph/schema/services/agent.py` | Ongeza `session_id` na `collection` kwenye `AgentRequest` | +| `trustgraph-base/trustgraph/messaging/translators/agent.py` | Sasisha `translator` kwa ajili ya sehemu mpya | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | Ongeza aina za `entity`, `agent predicates`, na `Document RAG predicates` | +| `trustgraph-base/trustgraph/provenance/triples.py` | Ongeza aina za `TG` kwenye `GraphRAG triple builders`, ongeza `Document RAG triple builders` | +| `trustgraph-base/trustgraph/provenance/uris.py` | Ongeza `Document RAG URI generators` | +| `trustgraph-base/trustgraph/provenance/__init__.py` | Export aina mpya, `predicates`, na `Document RAG functions` | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | Ongeza `explain_id` na `explain_graph` kwenye `DocumentRagResponse` | +| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | Sasisha `DocumentRagResponseTranslator` kwa ajili ya sehemu za `explainability` | +| `trustgraph-flow/trustgraph/agent/react/service.py` | Ongeza mzalishaji wa `explainability` + mantiki ya kurekodi | +| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | Ongeza `explainability callback` na toa `provenance triples` | +| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | Ongeza mzalishaji wa `explainability` na uunganishe `callback` | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | Shirikisha aina za `agent trace` | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | Orodha `agent sessions` pamoja na `GraphRAG` | + +## Faili Zilizoundwa + +| Faili | Madhumuni | +|------|---------| +| `trustgraph-base/trustgraph/provenance/agent.py` | Wazalishaji wa `triple` maalum kwa `agent` | + +## Mabadiliko ya CLI + +**Kugundua:** Maswali ya `GraphRAG` na `Agent` yana aina ya `tg:Question`. Hutofautishwa na: +1. Mfumo wa `URI`: `urn:trustgraph:agent:` dhidi ya `urn:trustgraph:question:` +2. Vipengele vilivyotokana: `tg:Analysis` (`agent`) dhidi ya `tg:Exploration` (`GraphRAG`) + +**`list_explain_traces.py`:** +- Inaonyesha safu ya Aina (Agent vs GraphRAG) + +**`show_explain_trace.py`:** +- Hugundua kiotomatiki aina ya `trace` +- Uonyesho wa `agent` unaonyesha: Swali → Hatua za uchambuzi → Hitimisho + +## Utangamano na Mifumo ya Zamani + +- `session_id` huenda kwa `""` - maombi ya zamani hufanya kazi, lakini hayata na `provenance` +- `collection` huenda kwa `"default"` - `fallback` inayofaa +- CLI hushughulikia aina zote za `trace` kwa utulivu + +## Uthibitisho + +```bash +# Run an agent query +tg-invoke-agent -q "What is the capital of France?" + +# List traces (should show agent sessions with Type column) +tg-list-explain-traces -U trustgraph -C default + +# Show agent trace +tg-show-explain-trace "urn:trustgraph:agent:xxx" +``` + +## Kazi Zinazotarajiwa (Sio Katika Mradi Huyu) + +- Utendakazi wa utegemezi wa DAG (wakati uchambuzi N hutumia matokeo kutoka kwa uchambuzi kadhaa uliopita) +- Uunganisho wa utambulisho wa zana maalum (KnowledgeQuery → faili yake ya GraphRAG) +- Utumaji wa utambulisho wa mtiririko (tumia kwa wakati, sio kwa wingi mwisho) diff --git a/docs/tech-specs/agent-explainability.tr.md b/docs/tech-specs/agent-explainability.tr.md new file mode 100644 index 00000000..60bff50e --- /dev/null +++ b/docs/tech-specs/agent-explainability.tr.md @@ -0,0 +1,272 @@ +# Ajan Açıklanabilirliği: Kaynak Kaydı + +## Genel Bakış + +Ajan oturumlarının izlenebilmesi ve GraphRAG ile aynı açıklanabilirlik altyapısı kullanılarak hata ayıklanabilmesi için, React ajan döngüsüne kaynak kaydı ekleyin. + +**Tasarım Kararları:** +- `urn:graph:retrieval`'a yazın (genel açıklanabilirlik grafiği) +- Şu anda doğrusal bağımlılık zinciri (analiz N → wasDerivedFrom → analiz N-1) +- Araçlar, kayıt alınmayan, opak kara kutulardır (sadece girdi/çıktı kaydedilir) +- DAG desteği, gelecekteki bir yinelemeye ertelenmiştir + +## Varlık Türleri + +Hem GraphRAG hem de Agent, TrustGraph'e özgü alt türlere sahip olan PROV-O'yu temel ontoloji olarak kullanır: + +### GraphRAG Türleri +| Varlık | PROV-O Türü | TG Türleri | Açıklama | +|--------|-------------|----------|-------------| +| Soru | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | Kullanıcının sorgusu | +| Keşif | `prov:Entity` | `tg:Exploration` | Bilgi grafiğinden alınan kenarlar | +| Odak | `prov:Entity` | `tg:Focus` | Akıl yürütmeyle seçilen kenarlar | +| Sentez | `prov:Entity` | `tg:Synthesis` | Sonuç | + +### Ajan Türleri +| Varlık | PROV-O Türü | TG Türleri | Açıklama | +|--------|-------------|----------|-------------| +| Soru | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | Kullanıcının sorgusu | +| Analiz | `prov:Entity` | `tg:Analysis` | Her düşünme/eylem/gözlem döngüsü | +| Sonuç | `prov:Entity` | `tg:Conclusion` | Sonuç | + +### Belge RAG Türleri +| Varlık | PROV-O Türü | TG Türleri | Açıklama | +|--------|-------------|----------|-------------| +| Soru | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | Kullanıcının sorgusu | +| Keşif | `prov:Entity` | `tg:Exploration` | Belge deposundan alınan parçalar | +| Sentez | `prov:Entity` | `tg:Synthesis` | Sonuç | + +**Not:** Belge RAG, GraphRAG'ın türlerinin bir alt kümesini kullanır (kenar seçimi/akıl yürütme aşaması olmadığından Odak adımı yoktur). + +### Soru Alt Türleri + +Tüm Soru varlıkları `tg:Question`'ı temel tür olarak paylaşır, ancak geri alma mekanizmasını tanımlamak için özel bir alt türe sahiptir: + +| Alt Tür | URI Kalıbı | Mekanizma | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | Bilgi grafiği RAG | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | Belge/parça RAG | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | ReAct ajanı | + +Bu, tüm soruların `tg:Question` aracılığıyla sorgulanabilmesini sağlarken, alt tür aracılığıyla belirli bir mekanizma ile filtrelenmesini sağlar. + +## Kaynak Modeli + +``` +Question (urn:trustgraph:agent:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasDerivedFrom + │ +Analysis1 (urn:trustgraph:agent:{uuid}/i1) + │ + │ tg:thought = "I need to query the knowledge base..." + │ tg:action = "knowledge-query" + │ tg:arguments = {"question": "..."} + │ tg:observation = "Result from tool..." + │ rdf:type = prov:Entity, tg:Analysis + │ + ↓ prov:wasDerivedFrom + │ +Analysis2 (urn:trustgraph:agent:{uuid}/i2) + │ ... + ↓ prov:wasDerivedFrom + │ +Conclusion (urn:trustgraph:agent:{uuid}/final) + │ + │ tg:answer = "The final response..." + │ rdf:type = prov:Entity, tg:Conclusion +``` + +### Belge RAG (Retrieval-Augmented Generation) Kaynak Modeli + +``` +Question (urn:trustgraph:docrag:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasGeneratedBy + │ +Exploration (urn:trustgraph:docrag:{uuid}/exploration) + │ + │ tg:chunkCount = 5 + │ tg:selectedChunk = "chunk-id-1" + │ tg:selectedChunk = "chunk-id-2" + │ ... + │ rdf:type = prov:Entity, tg:Exploration + │ + ↓ prov:wasDerivedFrom + │ +Synthesis (urn:trustgraph:docrag:{uuid}/synthesis) + │ + │ tg:content = "The synthesized answer..." + │ rdf:type = prov:Entity, tg:Synthesis +``` + +## Gerekli Değişiklikler + +### 1. Şema Değişiklikleri + +**Dosya:** `trustgraph-base/trustgraph/schema/services/agent.py` + +`AgentRequest`'ye `session_id` ve `collection` alanlarını ekleyin: +```python +@dataclass +class AgentRequest: + question: str = "" + state: str = "" + group: list[str] | None = None + history: list[AgentStep] = field(default_factory=list) + user: str = "" + collection: str = "default" # NEW: Collection for provenance traces + streaming: bool = False + session_id: str = "" # NEW: For provenance tracking across iterations +``` + +**Dosya:** `trustgraph-base/trustgraph/messaging/translators/agent.py` + +Çeviriciyi, `session_id` ve `collection`'i hem `to_pulsar()` hem de `from_pulsar()` içinde işleyebilecek şekilde güncelleyin. + +### 2. Ajan Hizmetine Açıklanabilirlik Üreticisini Ekle + +**Dosya:** `trustgraph-flow/trustgraph/agent/react/service.py` + +Bir "açıklanabilirlik" üreticisi kaydedin (GraphRAG ile aynı yapı): +```python +from ... base import ProducerSpec +from ... schema import Triples + +# In __init__: +self.register_specification( + ProducerSpec( + name = "explainability", + schema = Triples, + ) +) +``` + +### 3. Kaynak Üçlü Oluşturma + +**Dosya:** `trustgraph-base/trustgraph/provenance/agent.py` + +Yardımcı fonksiyonlar oluşturun (GraphRAG'in `question_triples`, `exploration_triples`, vb. gibi): +```python +def agent_session_triples(session_uri, query, timestamp): + """Generate triples for agent Question.""" + return [ + Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY), + Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION), + Triple(s=session_uri, p=TG_QUERY, o=query), + Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp), + ] + +def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation): + """Generate triples for one Analysis step.""" + return [ + Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS), + Triple(s=iteration_uri, p=TG_THOUGHT, o=thought), + Triple(s=iteration_uri, p=TG_ACTION, o=action), + Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)), + Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation), + Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] + +def agent_final_triples(final_uri, parent_uri, answer): + """Generate triples for Conclusion.""" + return [ + Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION), + Triple(s=final_uri, p=TG_ANSWER, o=answer), + Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] +``` + +### 4. Tür Tanımları + +**Dosya:** `trustgraph-base/trustgraph/provenance/namespaces.py` + +Açıklanabilirlik varlık türlerini ve ajan özniteliklerini ekleyin: +```python +# Explainability entity types (used by both GraphRAG and Agent) +TG_QUESTION = TG + "Question" +TG_EXPLORATION = TG + "Exploration" +TG_FOCUS = TG + "Focus" +TG_SYNTHESIS = TG + "Synthesis" +TG_ANALYSIS = TG + "Analysis" +TG_CONCLUSION = TG + "Conclusion" + +# Agent predicates +TG_THOUGHT = TG + "thought" +TG_ACTION = TG + "action" +TG_ARGUMENTS = TG + "arguments" +TG_OBSERVATION = TG + "observation" +TG_ANSWER = TG + "answer" +``` + +## Değiştirilen Dosyalar + +| Dosya | Değişiklik | +|------|--------| +| `trustgraph-base/trustgraph/schema/services/agent.py` | AgentRequest'e session_id ve collection eklendi | +| `trustgraph-base/trustgraph/messaging/translators/agent.py` | Yeni alanlar için çevirici güncellendi | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | Varlık türleri, ajan önişlemleri ve Document RAG önişlemleri eklendi | +| `trustgraph-base/trustgraph/provenance/triples.py` | GraphRAG üçlü oluşturucularına TG türleri eklendi, Document RAG üçlü oluşturucuları eklendi | +| `trustgraph-base/trustgraph/provenance/uris.py` | Document RAG URI oluşturucuları eklendi | +| `trustgraph-base/trustgraph/provenance/__init__.py` | Yeni türler, önişlemler ve Document RAG fonksiyonları dışa aktarıldı | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | DocumentRagResponse'a explain_id ve explain_graph eklendi | +| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | Açıklanabilirlik alanları için DocumentRagResponseTranslator güncellendi | +| `trustgraph-flow/trustgraph/agent/react/service.py` | Açıklanabilirlik üretici + kayıt mantığı eklendi | +| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | Açıklanabilirlik geri çağırması eklendi ve kaynak üçlüleri yayıldı | +| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | Açıklanabilirlik üretici eklendi ve geri çağırma ile bağlandı | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | Ajan izleme türleri işlendi | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | Ajan oturumları, GraphRAG ile birlikte listelendi | + +## Oluşturulan Dosyalar + +| Dosya | Amaç | +|------|---------| +| `trustgraph-base/trustgraph/provenance/agent.py` | Ajan özel üçlü oluşturucuları | + +## CLI Güncellemeleri + +**Algılama:** Hem GraphRAG hem de Ajan Soruları `tg:Question` türündedir. Aşağıdakilerle ayırt edilir: +1. URI kalıbı: `urn:trustgraph:agent:` vs `urn:trustgraph:question:` +2. Türetilen varlıklar: `tg:Analysis` (ajan) vs `tg:Exploration` (GraphRAG) + +**`list_explain_traces.py`:** +- Tür sütununu (Ajan vs GraphRAG) gösterir + +**`show_explain_trace.py`:** +- İzleme türünü otomatik olarak algılar +- Ajan işleme, şu öğeleri gösterir: Soru → Analiz adımı(ları) → Sonuç + +## Geriye Dönük Uyumluluk + +- `session_id` varsayılan olarak `""`'dir - eski istekler çalışır, ancak kaynak bilgisi olmayacaktır +- `collection` varsayılan olarak `"default"`'dir - makul bir yedekleme +- CLI, her iki izleme türünü de sorunsuz bir şekilde işler + +## Doğrulama + +```bash +# Run an agent query +tg-invoke-agent -q "What is the capital of France?" + +# List traces (should show agent sessions with Type column) +tg-list-explain-traces -U trustgraph -C default + +# Show agent trace +tg-show-explain-trace "urn:trustgraph:agent:xxx" +``` + +## Gelecek Çalışmalar (Bu PR'de Değil) + +- DAG bağımlılıkları (analiz N, birden fazla önceki analizden sonuçları kullandığında) +- Araçlara özel köken bağlantısı (KnowledgeQuery → GraphRAG izi) +- Akışlı köken yayını (sonunda toplu olarak değil, işlem sırasında yayınla) diff --git a/docs/tech-specs/agent-explainability.zh-cn.md b/docs/tech-specs/agent-explainability.zh-cn.md new file mode 100644 index 00000000..189a5fc1 --- /dev/null +++ b/docs/tech-specs/agent-explainability.zh-cn.md @@ -0,0 +1,272 @@ +# Agent Explainability: Provenance Recording + +## 概述 + +为使代理会话可追溯和可调试,并将代理循环中的溯源记录添加到 React 代理中,从而使用与 GraphRAG 相同的可解释性基础设施。 + +**设计决策:** +写入 `urn:graph:retrieval` (通用可解释性图) +目前采用线性依赖链 (分析 N → wasDerivedFrom → 分析 N-1) +工具是不可见的黑盒 (仅记录输入/输出) +DAG 支持计划在未来迭代中实现 + +## 实体类型 + +GraphRAG 和 Agent 都使用 PROV-O 作为基础本体,并具有 TrustGraph 特定的子类型: + +### GraphRAG 类型 +| 实体 | PROV-O 类型 | TG 类型 | 描述 | +|--------|-------------|----------|-------------| +| 问题 | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | 用户的查询 | +| 探索 | `prov:Entity` | `tg:Exploration` | 从知识图谱检索的边 | +| 重点 | `prov:Entity` | `tg:Focus` | 带有推理的选定边 | +| 合成 | `prov:Entity` | `tg:Synthesis` | 最终答案 | + +### Agent 类型 +| 实体 | PROV-O 类型 | TG 类型 | 描述 | +|--------|-------------|----------|-------------| +| 问题 | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | 用户的查询 | +| 分析 | `prov:Entity` | `tg:Analysis` | 每个思考/行动/观察周期 | +| 结论 | `prov:Entity` | `tg:Conclusion` | 最终答案 | + +### Document RAG 类型 +| 实体 | PROV-O 类型 | TG 类型 | 描述 | +|--------|-------------|----------|-------------| +| 问题 | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | 用户的查询 | +| 探索 | `prov:Entity` | `tg:Exploration` | 从文档存储中检索的块 | +| 合成 | `prov:Entity` | `tg:Synthesis` | 最终答案 | + +**注意:** Document RAG 使用 GraphRAG 类型的子集 (没有“重点”步骤,因为没有边选择/推理阶段)。 + +### 问题子类型 + +所有“问题”实体都共享 `tg:Question` 作为基本类型,但具有特定的子类型以标识检索机制: + +| 子类型 | URI 模式 | 机制 | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | 知识图谱 RAG | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | 文档/块 RAG | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | ReAct 代理 | + +这允许通过 `tg:Question` 查询所有问题,同时通过子类型过滤特定机制。 + +## 溯源模型 + +``` +Question (urn:trustgraph:agent:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasDerivedFrom + │ +Analysis1 (urn:trustgraph:agent:{uuid}/i1) + │ + │ tg:thought = "I need to query the knowledge base..." + │ tg:action = "knowledge-query" + │ tg:arguments = {"question": "..."} + │ tg:observation = "Result from tool..." + │ rdf:type = prov:Entity, tg:Analysis + │ + ↓ prov:wasDerivedFrom + │ +Analysis2 (urn:trustgraph:agent:{uuid}/i2) + │ ... + ↓ prov:wasDerivedFrom + │ +Conclusion (urn:trustgraph:agent:{uuid}/final) + │ + │ tg:answer = "The final response..." + │ rdf:type = prov:Entity, tg:Conclusion +``` + +### 文档检索增强生成(RAG)溯源模型 + +``` +Question (urn:trustgraph:docrag:{uuid}) + │ + │ tg:query = "User's question" + │ prov:startedAtTime = timestamp + │ rdf:type = prov:Activity, tg:Question + │ + ↓ prov:wasGeneratedBy + │ +Exploration (urn:trustgraph:docrag:{uuid}/exploration) + │ + │ tg:chunkCount = 5 + │ tg:selectedChunk = "chunk-id-1" + │ tg:selectedChunk = "chunk-id-2" + │ ... + │ rdf:type = prov:Entity, tg:Exploration + │ + ↓ prov:wasDerivedFrom + │ +Synthesis (urn:trustgraph:docrag:{uuid}/synthesis) + │ + │ tg:content = "The synthesized answer..." + │ rdf:type = prov:Entity, tg:Synthesis +``` + +## 需要修改的内容 + +### 1. 模式更改 + +**文件:** `trustgraph-base/trustgraph/schema/services/agent.py` + +向 `AgentRequest` 添加 `session_id` 和 `collection` 字段: +```python +@dataclass +class AgentRequest: + question: str = "" + state: str = "" + group: list[str] | None = None + history: list[AgentStep] = field(default_factory=list) + user: str = "" + collection: str = "default" # NEW: Collection for provenance traces + streaming: bool = False + session_id: str = "" # NEW: For provenance tracking across iterations +``` + +**文件:** `trustgraph-base/trustgraph/messaging/translators/agent.py` + +更新翻译器,使其能够处理 `session_id` 和 `collection`,并在 `to_pulsar()` 和 `from_pulsar()` 中均能正确处理。 + +### 2. 向 Agent Service 添加可解释性生产者 + +**文件:** `trustgraph-flow/trustgraph/agent/react/service.py` + +注册一个“可解释性”生产者(与 GraphRAG 相同模式): +```python +from ... base import ProducerSpec +from ... schema import Triples + +# In __init__: +self.register_specification( + ProducerSpec( + name = "explainability", + schema = Triples, + ) +) +``` + +### 3. 溯源三元组生成 + +**文件:** `trustgraph-base/trustgraph/provenance/agent.py` + +创建辅助函数(类似于 GraphRAG 的 `question_triples`、`exploration_triples` 等): +```python +def agent_session_triples(session_uri, query, timestamp): + """Generate triples for agent Question.""" + return [ + Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY), + Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION), + Triple(s=session_uri, p=TG_QUERY, o=query), + Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp), + ] + +def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation): + """Generate triples for one Analysis step.""" + return [ + Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS), + Triple(s=iteration_uri, p=TG_THOUGHT, o=thought), + Triple(s=iteration_uri, p=TG_ACTION, o=action), + Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)), + Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation), + Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] + +def agent_final_triples(final_uri, parent_uri, answer): + """Generate triples for Conclusion.""" + return [ + Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY), + Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION), + Triple(s=final_uri, p=TG_ANSWER, o=answer), + Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri), + ] +``` + +### 4. 类型定义 + +**文件:** `trustgraph-base/trustgraph/provenance/namespaces.py` + +添加可解释性实体类型和代理谓词: +```python +# Explainability entity types (used by both GraphRAG and Agent) +TG_QUESTION = TG + "Question" +TG_EXPLORATION = TG + "Exploration" +TG_FOCUS = TG + "Focus" +TG_SYNTHESIS = TG + "Synthesis" +TG_ANALYSIS = TG + "Analysis" +TG_CONCLUSION = TG + "Conclusion" + +# Agent predicates +TG_THOUGHT = TG + "thought" +TG_ACTION = TG + "action" +TG_ARGUMENTS = TG + "arguments" +TG_OBSERVATION = TG + "observation" +TG_ANSWER = TG + "answer" +``` + +## 文件修改 + +| 文件 | 更改 | +|------|--------| +| `trustgraph-base/trustgraph/schema/services/agent.py` | 向 AgentRequest 添加 session_id 和 collection | +| `trustgraph-base/trustgraph/messaging/translators/agent.py` | 更新翻译器以适应新字段 | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | 添加实体类型、agent谓词和 Document RAG 谓词 | +| `trustgraph-base/trustgraph/provenance/triples.py` | 向 GraphRAG 三元组构建器添加 TG 类型,添加 Document RAG 三元组构建器 | +| `trustgraph-base/trustgraph/provenance/uris.py` | 添加 Document RAG URI 生成器 | +| `trustgraph-base/trustgraph/provenance/__init__.py` | 导出新类型、谓词和 Document RAG 函数 | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | 向 DocumentRagResponse 添加 explain_id 和 explain_graph | +| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | 更新 DocumentRagResponseTranslator 以适应可解释性字段 | +| `trustgraph-flow/trustgraph/agent/react/service.py` | 添加可解释性生产者 + 记录逻辑 | +| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | 添加可解释性回调并发出溯源三元组 | +| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | 添加可解释性生产者并连接回调 | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | 处理 agent 跟踪类型 | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | 在 GraphRAG 旁边列出 agent 会话 | + +## 创建的文件 + +| 文件 | 目的 | +|------|---------| +| `trustgraph-base/trustgraph/provenance/agent.py` | Agent 相关的三元组生成器 | + +## CLI 更新 + +**检测:** 无论是 GraphRAG 还是 Agent 问题,都具有 `tg:Question` 类型。通过以下方式区分: +1. URI 模式:`urn:trustgraph:agent:` vs `urn:trustgraph:question:` +2. 派生实体:`tg:Analysis` (agent) vs `tg:Exploration` (GraphRAG) + +**`list_explain_traces.py`:** +显示类型列(Agent vs GraphRAG) + +**`show_explain_trace.py`:** +自动检测跟踪类型 +Agent 渲染显示:问题 → 分析步骤(s) → 结论 + +## 向后兼容性 + +`session_id` 默认为 `""` - 旧请求有效,但将不具有溯源信息 +`collection` 默认为 `"default"` - 合理的备选方案 +CLI 能够优雅地处理两种跟踪类型 + +## 验证 + +```bash +# Run an agent query +tg-invoke-agent -q "What is the capital of France?" + +# List traces (should show agent sessions with Type column) +tg-list-explain-traces -U trustgraph -C default + +# Show agent trace +tg-show-explain-trace "urn:trustgraph:agent:xxx" +``` + +## 未来工作(不在本次 PR 中) + +DAG 依赖关系(当分析 N 使用来自多个先前分析的结果时) +特定于工具的溯源链接(KnowledgeQuery → 它的 GraphRAG 跟踪) +流式溯源输出(在过程中输出,而不是在最后批量输出) diff --git a/docs/tech-specs/architecture-principles.ar.md b/docs/tech-specs/architecture-principles.ar.md new file mode 100644 index 00000000..f4399d0d --- /dev/null +++ b/docs/tech-specs/architecture-principles.ar.md @@ -0,0 +1,106 @@ +# أسس هيكل الرسم البياني للمعرفة + +## الأساس الأول: نموذج الرسم البياني للعلاقة بين الموضوع والمسند والموضوع (SPO) +**القرار**: اعتماد نموذج SPO/RDF كنموذج تمثيل المعرفة الأساسي + +**السبب**: +يوفر أقصى قدر من المرونة وقابلية التشغيل البيني مع تقنيات الرسم البياني الحالية +يمكّن الترجمة السلسة إلى لغات استعلام عن الرسم البياني الأخرى (مثل SPO → Cypher، ولكن ليس العكس) +يخلق أساسًا "يفتح الكثير" من القدرات اللاحقة +يدعم كل من علاقات العقدة إلى العقدة (SPO) وعلاقات العقدة إلى القيمة الحرفية (RDF) + +**التنفيذ**: +الهيكل الأساسي للبيانات: `node → edge → {node | literal}` +الحفاظ على التوافق مع معايير RDF مع دعم عمليات SPO الموسعة + +## الأساس الثاني: تكامل الرسم البياني الأصلي لنماذج اللغة الكبيرة (LLM) +**القرار**: تحسين هيكل وعمليات الرسم البياني للتفاعل مع نماذج اللغة الكبيرة + +**السبب**: +الحالة الرئيسية هي تفاعل نماذج اللغة الكبيرة مع الرسوم البيانية للمعرفة +يجب أن تعطي خيارات تقنية الرسم البياني الأولوية لتوافق نماذج اللغة الكبيرة على اعتبارات أخرى +يمكّن سير عمل معالجة اللغة الطبيعية التي تستفيد من المعرفة المنظمة + +**التنفيذ**: +تصميم مخططات الرسم البياني التي يمكن لنماذج اللغة الكبيرة الاستدلال عليها بشكل فعال +التحسين لأنماط التفاعل الشائعة لنماذج اللغة الكبيرة + +## الأساس الثالث: التنقل في الرسم البياني القائم على التضمين +**القرار**: تنفيذ تعيين مباشر من استعلامات اللغة الطبيعية إلى عقد الرسم البياني عبر التضمينات + +**السبب**: +يمكّن المسار الأبسط من استعلام معالجة اللغة الطبيعية إلى التنقل في الرسم البياني +يتجنب خطوات توليد استعلام وسيطة معقدة +يوفر قدرات بحث دلالي فعالة داخل هيكل الرسم البياني + +**التنفيذ**: +`NLP Query → Graph Embeddings → Graph Nodes` +الحفاظ على تمثيلات التضمين لجميع كيانات الرسم البياني +دعم مطابقة تشابه دلالي مباشر لحل الاستعلامات + +## الأساس الرابع: حل الكيانات الموزع مع المعرفات الحتمية +**القرار**: دعم استخراج المعرفة المتوازي مع تحديد الكيانات الحتمي (قاعدة 80٪) + +**السبب**: +**مثالي**: يتيح استخراج العملية الفردية مع رؤية حالة كاملة حل الكيانات المثالي +**الواقع**: تتطلب متطلبات قابلية التوسع قدرات معالجة متوازية +**حل وسط**: التصميم من أجل تحديد الكيانات الحتمي عبر العمليات الموزعة + +**التنفيذ**: +تطوير آليات لتوليد معرفات متسقة وفريدة عبر أدوات استخراج المعرفة المختلفة +يجب أن يتم حل نفس الكيان المذكور في عمليات مختلفة إلى نفس المعرف +الاعتراف بأنه قد تتطلب ~20٪ من الحالات الخاصة نماذج معالجة بديلة +تصميم آليات احتياطية لسيناريوهات حل الكيانات المعقدة + +## الأساس الخامس: بنية قائمة على الأحداث مع النشر والاشتراك +**القرار**: تنفيذ نظام رسائل النشر والاشتراك لتنسيق النظام + +**السبب**: +يمكّن الفصل بين مكونات استخراج وتخزين واستعلام المعرفة +يدعم التحديثات والإشعارات في الوقت الفعلي عبر النظام +يسهل سير عمل معالجة موزعة وقابلة للتطوير + +**التنفيذ**: +تنسيق مدفوع بالرسائل بين مكونات النظام +تدفقات الأحداث لتحديثات المعرفة وإكمال الاستخراج ونتائج الاستعلام + +## الأساس السادس: تواصل الوكيل القابل لإعادة الدخول +**القرار**: دعم عمليات النشر والاشتراك القابلة لإعادة الدخول لمعالجة قائمة على الوكلاء + +**السبب**: +يمكّن سير عمل الوكيل المعقد حيث يمكن للوكلاء تشغيل والرد على بعضهم البعض +يدعم خطوط أنابيب معالجة المعرفة المعقدة والمتعددة الخطوات +يسمح بأنماط المعالجة التكرارية والتكرارية + +**التنفيذ**: +يجب أن يتعامل نظام النشر والاشتراك مع المكالمات القابلة لإعادة الدخول بأمان +آليات تنسيق الوكيل التي تمنع الحلقات اللانهائية +دعم تنسيق سير عمل الوكيل + +## الأساس السابع: تكامل متجر البيانات العمودي +**القرار**: ضمان توافق الاستعلام مع أنظمة التخزين العمودية + +**السبب**: +يمكّن الاستعلامات التحليلية الفعالة على مجموعات بيانات المعرفة الكبيرة +يدعم حالات استخدام ذكاء الأعمال وإعداد التقارير +يربط بين تمثيل المعرفة القائم على الرسم البياني وسير العمل التحليلي التقليدي + +**التنفيذ**: +طبقة ترجمة الاستعلام: استعلامات الرسم البياني → استعلامات عمودية +استراتيجية تخزين هجينة تدعم عمليات الرسم البياني وأحمال العمل التحليلية +الحفاظ على أداء الاستعلام عبر كلا النماذجين + +-- + +## ملخص مبادئ البنية + +1. **المرونة أولاً**: يوفر نموذج SPO أقصى قدر من القدرة على التكيف +2. **التحسين لنماذج اللغة الكبيرة**: تأخذ جميع القرارات التصميمية في الاعتبار متطلبات تفاعل نماذج اللغة الكبيرة +3. **الكفاءة الدلالية**: تعيين مباشر من التضمين إلى العقدة لأداء استعلام أمثل +4. **قابلية التوسع العملية**: الموازنة بين الدقة المثالية والمعالجة الموزعة العملية +5. **التنسيق القائم على الأحداث**: يمكّن النشر والاشتراك من الفصل وقابلية التوسع +6. **صديقة للوكيل**: دعم سير عمل معالجة متعددة الوكلاء +7. **التوافق التحليلي**: ربط بين نماذج الرسم البياني والأعمدة للاستعلامات الشاملة + +تحدد هذه الأسس بنية رسم بياني للمعرفة تحقق التوازن بين الدقة النظرية ومتطلبات قابلية التوسع العملية، ومحسنة للتكامل مع نماذج اللغة الكبيرة والمعالجة الموزعة. + diff --git a/docs/tech-specs/architecture-principles.es.md b/docs/tech-specs/architecture-principles.es.md new file mode 100644 index 00000000..2b4a713e --- /dev/null +++ b/docs/tech-specs/architecture-principles.es.md @@ -0,0 +1,106 @@ +# Fundamentos de la Arquitectura del Gráfico de Conocimiento + +## Fundamento 1: Modelo de Gráfico Sujeto-Predicado-Objeto (SPO) +**Decisión**: Adoptar SPO/RDF como el modelo de representación de conocimiento central. + +**Justificación**: +Proporciona la máxima flexibilidad e interoperabilidad con las tecnologías de gráficos existentes. +Permite la traducción fluida a otros lenguajes de consulta de gráficos (por ejemplo, SPO → Cypher, pero no al revés). +Crea una base que "desbloquea muchas" capacidades posteriores. +Admite tanto relaciones de nodo a nodo (SPO) como relaciones de nodo a literal (RDF). + +**Implementación**: +Estructura de datos central: `node → edge → {node | literal}` +Mantener la compatibilidad con los estándares RDF al tiempo que se admiten operaciones SPO extendidas. + +## Fundamento 2: Integración Nativa del Gráfico de Conocimiento con LLM +**Decisión**: Optimizar la estructura y las operaciones del gráfico de conocimiento para la interacción con LLM. + +**Justificación**: +El caso de uso principal implica que los LLM interactúen con los gráficos de conocimiento. +Las opciones de tecnología de gráficos deben priorizar la compatibilidad con LLM por encima de otras consideraciones. +Permite flujos de trabajo de procesamiento del lenguaje natural que aprovechan el conocimiento estructurado. + +**Implementación**: +Diseñar esquemas de gráficos que los LLM puedan comprender y razonar eficazmente. +Optimizar para patrones de interacción comunes con LLM. + +## Fundamento 3: Navegación del Gráfico Basada en Incrustaciones +**Decisión**: Implementar un mapeo directo de las consultas de lenguaje natural a los nodos del gráfico a través de incrustaciones. + +**Justificación**: +Permite la ruta más sencilla posible desde la consulta de PNL hasta la navegación del gráfico. +Evita pasos complejos de generación de consultas intermedias. +Proporciona capacidades de búsqueda semántica eficientes dentro de la estructura del gráfico. + +**Implementación**: +`NLP Query → Graph Embeddings → Graph Nodes` +Mantener representaciones de incrustación para todas las entidades del gráfico. +Admitir la coincidencia de similitud semántica directa para la resolución de consultas. + +## Fundamento 4: Resolución de Entidades Distribuidas con Identificadores Deterministas +**Decisión**: Admitir la extracción de conocimiento en paralelo con la identificación determinista de entidades (regla del 80%). + +**Justificación**: +**Ideal**: La extracción en un solo proceso con visibilidad completa del estado permite una resolución de entidades perfecta. +**Realidad**: Los requisitos de escalabilidad exigen capacidades de procesamiento en paralelo. +**Compromiso**: Diseñar para la identificación determinista de entidades en procesos distribuidos. + +**Implementación**: +Desarrollar mecanismos para generar identificadores consistentes y únicos en diferentes extractores de conocimiento. +La misma entidad mencionada en diferentes procesos debe resolverse en el mismo identificador. +Reconocer que aproximadamente el 20% de los casos extremos pueden requerir modelos de procesamiento alternativos. +Diseñar mecanismos de respaldo para escenarios complejos de resolución de entidades. + +## Fundamento 5: Arquitectura Orientada a Eventos con Publicación-Suscripción +**Decisión**: Implementar un sistema de mensajería de publicación-suscripción para la coordinación del sistema. + +**Justificación**: +Permite un acoplamiento débil entre los componentes de extracción, almacenamiento y consulta de conocimiento. +Admite actualizaciones y notificaciones en tiempo real en todo el sistema. +Facilita flujos de trabajo de procesamiento distribuidos y escalables. + +**Implementación**: +Coordinación basada en mensajes entre los componentes del sistema. +Flujos de eventos para actualizaciones de conocimiento, finalización de la extracción y resultados de consultas. + +## Fundamento 6: Comunicación de Agentes Reentrantes +**Decisión**: Admitir operaciones de publicación-suscripción reentrantes para el procesamiento basado en agentes. + +**Justificación**: +Permite flujos de trabajo sofisticados de agentes donde los agentes pueden activar y responder entre sí. +Admite canalizaciones complejas de procesamiento de conocimiento con varios pasos. +Permite patrones de procesamiento recursivos e iterativos. + +**Implementación**: +El sistema de publicación-suscripción debe manejar las llamadas reentrantes de forma segura. +Mecanismos de coordinación de agentes que previenen bucles infinitos. +Soporte para la orquestación de flujos de trabajo de agentes. + +## Fundamento 7: Integración con Almacenes de Datos Columnares +**Decisión**: Asegurar la compatibilidad de las consultas con los sistemas de almacenamiento columnar. + +**Justificación**: +Permite consultas analíticas eficientes sobre grandes conjuntos de datos de conocimiento. +Admite casos de uso de inteligencia empresarial e informes. +Une la representación de conocimiento basada en gráficos con los flujos de trabajo analíticos tradicionales. + +**Implementación**: +Capa de traducción de consultas: Consultas de gráfico → Consultas de columna. +Estrategia de almacenamiento híbrida que admite tanto operaciones de gráfico como cargas de trabajo analíticas. +Mantener el rendimiento de las consultas en ambos paradigmas. + +-- + +## Resumen de los Principios de la Arquitectura + +1. **Flexibilidad Primero**: El modelo SPO/RDF proporciona la máxima adaptabilidad. +2. **Optimización para LLM**: Todas las decisiones de diseño consideran los requisitos de interacción con LLM. +3. **Eficiencia Semántica**: Mapeo directo de incrustaciones a nodos para un rendimiento de consulta óptimo. +4. **Escalabilidad Pragmática**: Equilibrar la precisión perfecta con el procesamiento distribuido práctico. +5. **Coordinación Orientada a Eventos**: La publicación-suscripción permite un acoplamiento débil y la escalabilidad. +6. **Amigable para Agentes**: Admite flujos de trabajo complejos de procesamiento basados en agentes. +7. **Compatibilidad Analítica**: Une los paradigmas de gráficos y columnas para consultas integrales. + +Estos fundamentos establecen una arquitectura de gráfico de conocimiento que equilibra la rigurosidad teórica con los requisitos prácticos de escalabilidad, optimizada para la integración con LLM y el procesamiento distribuido. + diff --git a/docs/tech-specs/architecture-principles.he.md b/docs/tech-specs/architecture-principles.he.md new file mode 100644 index 00000000..fdbac4fa --- /dev/null +++ b/docs/tech-specs/architecture-principles.he.md @@ -0,0 +1,106 @@ +# יסודות ארכיטקטורת גרף ידע + +## יסוד 1: מודל גרף נושא-תכונה-אובייקט (SPO) +**החלטה**: לאמץ את מודל SPO/RDF כמודל הייצוג הבסיסי של ידע. + +**הצדקה**: +מספק גמישות מרבית ותאימות עם טכנולוגיות גרף קיימות. +מאפשר המרה חלקה לשפות שאילתות גרף אחרות (לדוגמה, SPO → Cypher, אך לא להיפך). +יוצר בסיס ש"פותח הרבה" יכולות נלוות. +תומך הן בקשרים בין צמתים (SPO) והן בקשרים בין צמתים לערכים (RDF). + +**יישום**: +מבנה נתונים מרכזי: `node → edge → {node | literal}` +שמירה על תאימות לתקני RDF תוך תמיכה בפעולות SPO מורחבות. + +## יסוד 2: שילוב גרף ידע מותאם למודלי שפה גדולים (LLM) +**החלטה**: אופטימיזציה של מבנה ותפעול גרף ידע לאינטראקציה עם LLM. + +**הצדקה**: +מקרה שימוש עיקרי כולל LLM באינטראקציה עם גרפי ידע. +בחירות טכנולוגיות גרף חייבות לתעדף תאימות ל-LLM על פני שיקולים אחרים. +מאפשר זרימות עבודה של עיבוד שפה טבעית המנצלות ידע מובנה. + +**יישום**: +תכנון סכימות גרף ש-LLM יכולים להסיק מהן בצורה יעילה. +אופטימיזציה לדפוסי אינטראקציה נפוצים של LLM. + +## יסוד 3: ניווט גרף מבוסס הטבעות (Embeddings) +**החלטה**: יישום מיפוי ישיר משאילתות בשפה טבעית לצמתים בגרף באמצעות הטבעות. + +**הצדקה**: +מאפשר את הנתיב הפשוט ביותר משאילת NLP לניווט בגרף. +נמנע משלבי יצירת שאילתות ביניים מורכבים. +מספק יכולות חיפוש סמנטיות יעילות בתוך מבנה הגרף. + +**יישום**: +`NLP Query → Graph Embeddings → Graph Nodes` +שמירה על ייצוגי הטבעות עבור כל ישויות הגרף. +תמיכה בהתאמת דמיון סמנטי ישירה לפתרון שאילתות. + +## יסוד 4: פתרון ישויות מבוזר עם מזהים דטרמיניסטיים +**החלטה**: תמיכה בחילוץ ידע מקבילי עם זיהוי ישויות דטרמיניסטי (כלל 80%). + +**הצדקה**: +**אידיאלי**: חילוץ בתהליך יחיד עם נראות של מצב מלא מאפשר פתרון ישויות מושלם. +**מציאות**: דרישות סקיילביליות מחייבות יכולות עיבוד מקבילי. +**פשרה**: תכנון לזיהוי ישויות דטרמיניסטי בכל תהליכים מבוזרים. + +**יישום**: +פיתוח מנגנונים ליצירת מזהים עקביים וייחודיים בכל חולצי הידע. +אותה ישות המוזכרת בתהליכים שונים חייבת להתפרש לאותו מזהה. +יש להכיר בכך ש~20% מהמקרים המיוחדים עשויים לדרוש מודלי עיבוד חלופיים. +תכנון מנגנוני ברירת מחדל עבור תרחישי פתרון ישויות מורכבים. + +## יסוד 5: ארכיטקטורה מונעת אירועים עם פרסום-מנוי +**החלטה**: יישום מערכת הודעות מבוססת פרסום-מנוי לתיאום מערכות. + +**הצדקה**: +מאפשר צימוד רופף בין רכיבי חילוץ, אחסון ושאילתות ידע. +תומך בעדכונים והתראות בזמן אמת ברחבי המערכת. +מקל על זרימות עבודה מבוזרות וניתנות להרחבה. + +**יישום**: +תיאום מונחה הודעות בין רכיבי מערכת. +זרמי אירועים לעדכוני ידע, השלמת חילוץ ושליחת תוצאות שאילתות. + +## יסוד 6: תקשורת סוכנים חוזרת +**החלטה**: תמיכה בפעולות פרסום-מנוי חוזרות לעיבוד מבוסס סוכנים. + +**הצדקה**: +מאפשר זרימות עבודה מורכבות של סוכנים שבהם סוכנים יכולים להפעיל ולהגיב זה לזה. +תומך בצינורות עיבוד ידע מורכבים, רב-שלביים. +מאפשר דפוסי עיבוד רקורסיביים ואיטרטיביים. + +**יישום**: +מערכת הפרסום-מנוי חייבת לטפל בשיחות חוזרות בצורה בטוחה. +מנגנוני תיאום סוכנים שמונעים לולאות אינסופיות. +תמיכה בתיאום זרימות עבודה של סוכנים. + +## יסוד 7: שילוב עם חנות נתונים טבלאית +**החלטה**: הבטחת תאימות שאילתות למערכות אחסון טבלאיות. + +**הצדקה**: +מאפשר שאילתות אנליטיות יעילות על פני מערכי ידע גדולים. +תומך במקרי שימוש של מודיעין עסקי ודיווח. +גשר בין ייצוג ידע מבוסס גרף לבין זרימות עבודה אנליטיות מסורתיות. + +**יישום**: +שכבת תרגום שאילתות: שאילתות גרף → שאילתות טבלאיות. +אסטרטגיית אחסון היברידית התומכת הן בפעולות גרף והן בעומסי עבודה אנליטיים. +שמירה על ביצועי שאילתות בשני הפרדיגמות. + +-- + +## סיכום עקרונות ארכיטקטורה + +1. **גמישות ראשית**: מודל SPO/RDF מספק יכולת הסתגלות מרבית. +2. **אופטימיזציה ל-LLM**: כל החלטות התכנון מתייחסות לאינטראקציה עם LLM. +3. **ניווט יעיל**: שימוש בטבעות (Embeddings) לניווט יעיל בגרף. +4. **פתרון ישויות מבוזר**: תמיכה בחילוץ ידע מקבילי עם מזהים דטרמיניסטיים. +5. **תיאום מערכות**: שימוש במערכת הודעות מבוססת פרסום-מנוי. +6. **עיבוד סוכנים חוזר**: תמיכה בפעולות פרסום-מנוי חוזרות לעיבוד מבוסס סוכנים. +7. **תאימות שאילתות**: הבטחת תאימות שאילתות למערכות אחסון טבלאיות. + +יסודות אלה מציבים ארכיטקטורת גרף ידע המאזנת בין דיוק תיאורטי לדרישות מדרגיות מעשיות, ומותאמת לאינטגרציה עם מודלי שפה גדולים (LLM) ולעיבוד מבוזר. + diff --git a/docs/tech-specs/architecture-principles.hi.md b/docs/tech-specs/architecture-principles.hi.md new file mode 100644 index 00000000..9b3e8d5e --- /dev/null +++ b/docs/tech-specs/architecture-principles.hi.md @@ -0,0 +1,106 @@ +# नॉलेज ग्राफ आर्किटेक्चर फाउंडेशन + +## फाउंडेशन 1: सब्जेक्ट-प्रेडिकेट-ऑब्जेक्ट (एसपीओ) ग्राफ मॉडल +**निर्णय**: एस.पी.ओ./आर.डी.एफ. को मुख्य नॉलेज रिप्रेजेंटेशन मॉडल के रूप में अपनाएं + +**तर्क**: +यह अधिकतम लचीलापन और मौजूदा ग्राफ तकनीकों के साथ इंटरऑपरेबिलिटी प्रदान करता है। +यह अन्य ग्राफ क्वेरी भाषाओं (जैसे, एस.पी.ओ. → साइफर, लेकिन इसके विपरीत नहीं) में सहज अनुवाद को सक्षम बनाता है। +यह एक ऐसा आधार बनाता है जो "बहुत सारी" डाउनस्ट्रीम क्षमताओं को "अनलॉक" करता है। +यह नोड-टू-नोड संबंधों (एस.पी.ओ.) और नोड-टू-लिटरल संबंधों (आर.डी.एफ.) दोनों का समर्थन करता है। + +**कार्यान्वयन**: +मुख्य डेटा संरचना: `node → edge → {node | literal}` +विस्तारित एस.पी.ओ. ऑपरेशनों का समर्थन करते हुए आर.डी.एफ. मानकों के साथ अनुकूलता बनाए रखें। + +## फाउंडेशन 2: एलएलएम-नेटिव नॉलेज ग्राफ इंटीग्रेशन +**निर्णय**: एलएलएम इंटरैक्शन के लिए नॉलेज ग्राफ संरचना और ऑपरेशनों को अनुकूलित करें + +**तर्क**: +प्राथमिक उपयोग मामला एलएलएम का नॉलेज ग्राफ के साथ इंटरफेस करना है। +ग्राफ तकनीक विकल्पों को अन्य विचारों की तुलना में एलएलएम अनुकूलता को प्राथमिकता देनी चाहिए। +यह प्राकृतिक भाषा प्रसंस्करण वर्कफ़्लो को संरचित ज्ञान का लाभ उठाने में सक्षम बनाता है। + +**कार्यान्वयन**: +ऐसे ग्राफ स्कीमा डिज़ाइन करें जिन्हें एलएलएम प्रभावी ढंग से तर्क दे सकें। +सामान्य एलएलएम इंटरैक्शन पैटर्न के लिए अनुकूलित करें। + +## फाउंडेशन 3: एम्बेडिंग-आधारित ग्राफ नेविगेशन +**निर्णय**: प्राकृतिक भाषा प्रश्नों को एम्बेडिंग के माध्यम से ग्राफ नोड्स पर सीधे मैप करें + +**तर्क**: +यह एनएलपी क्वेरी से ग्राफ नेविगेशन के लिए सबसे सरल पथ को सक्षम करता है। +जटिल मध्यवर्ती क्वेरी पीढ़ी चरणों से बचें। +ग्राफ संरचना के भीतर कुशल सिमेंटिक खोज क्षमताओं को प्रदान करता है। + +**कार्यान्वयन**: +`NLP Query → Graph Embeddings → Graph Nodes` +सभी ग्राफ एंटिटीज के लिए एम्बेडिंग रिप्रेजेंटेशन बनाए रखें। +क्वेरी रिज़ॉल्यूशन के लिए प्रत्यक्ष सिमेंटिक समानता मिलान का समर्थन करें। + +## फाउंडेशन 4: डिस्ट्रीब्यूटेड एंटिटी रिज़ॉल्यूशन विद डिटर्मिनिस्टिक आइडेंटिफायर्स +**निर्णय**: डिस्ट्रीब्यूटेड एंटिटी आइडेंटिफिकेशन (80% नियम) के साथ समानांतर नॉलेज एक्सट्रैक्शन का समर्थन करें + +**तर्क**: +**आदर्श**: पूर्ण राज्य दृश्यता के साथ सिंगल-प्रोसेस एक्सट्रैक्शन सही एंटिटी रिज़ॉल्यूशन को सक्षम करता है। +**वास्तविकता**: स्केलेबिलिटी आवश्यकताओं के लिए समानांतर प्रसंस्करण क्षमताओं की आवश्यकता होती है। +**समझौता**: वितरित प्रक्रियाओं में नियतात्मक एंटिटी पहचान के लिए डिज़ाइन करें। + +**कार्यान्वयन**: +ऐसे तंत्र विकसित करें जो विभिन्न नॉलेज एक्सट्रैक्टर्स में सुसंगत, अद्वितीय पहचानकर्ता उत्पन्न करते हैं। +विभिन्न प्रक्रियाओं में उल्लिखित एक ही एंटिटी को समान पहचानकर्ता पर हल किया जाना चाहिए। +इस बात को स्वीकार करें कि ~20% एज केस के लिए वैकल्पिक प्रसंस्करण मॉडल की आवश्यकता हो सकती है। +जटिल एंटिटी रिज़ॉल्यूशन परिदृश्यों के लिए फॉलबैक तंत्र डिज़ाइन करें। + +## फाउंडेशन 5: इवेंट-ड्रिवन आर्किटेक्चर विद पब्लिश-सब्सक्राइब +**निर्णय**: सिस्टम समन्वय के लिए एक पब-सब मैसेजिंग सिस्टम लागू करें + +**तर्क**: +यह नॉलेज एक्सट्रैक्शन, स्टोरेज और क्वेरी घटकों के बीच ढीला युग्मन को सक्षम करता है। +यह पूरे सिस्टम में रीयल-टाइम अपडेट और नोटिफिकेशन का समर्थन करता है। +यह स्केलेबल, वितरित प्रसंस्करण वर्कफ़्लो को सुविधाजनक बनाता है। + +**कार्यान्वयन**: +सिस्टम घटकों के बीच मैसेज-ड्रिवन समन्वय। +नॉलेज अपडेट, एक्सट्रैक्शन पूरा होने और क्वेरी परिणामों के लिए इवेंट स्ट्रीम। + +## फाउंडेशन 6: रीएंट्रेंट एजेंट कम्युनिकेशन +**निर्णय**: एजेंट-आधारित प्रसंस्करण के लिए रीएंट्रेंट पब-सब ऑपरेशंस का समर्थन करें + +**तर्क**: +यह परिष्कृत एजेंट वर्कफ़्लो को सक्षम करता है जहां एजेंट एक-दूसरे को ट्रिगर और प्रतिक्रिया कर सकते हैं। +यह जटिल, बहु-चरणीय नॉलेज प्रोसेसिंग पाइपलाइनों का समर्थन करता है। +यह पुनरावर्ती और पुनरावृत्त प्रसंस्करण पैटर्न की अनुमति देता है। + +**कार्यान्वयन**: +पब-सब सिस्टम को सुरक्षित रूप से रीएंट्रेंट कॉल को संभालना चाहिए। +एजेंट समन्वय तंत्र जो अनंत लूप को रोकते हैं। +एजेंट वर्कफ़्लो ऑर्केस्ट्रेशन के लिए समर्थन। + +## फाउंडेशन 7: कॉलम डेटा स्टोर इंटीग्रेशन +**निर्णय**: कॉलम स्टोरेज सिस्टम के साथ क्वेरी अनुकूलता सुनिश्चित करें + +**तर्क**: +यह बड़े नॉलेज डेटासेट पर कुशल विश्लेषणात्मक प्रश्नों को सक्षम करता है। +यह बिजनेस इंटेलिजेंस और रिपोर्टिंग उपयोग मामलों का समर्थन करता है। +यह ग्राफ-आधारित नॉलेज रिप्रेजेंटेशन को पारंपरिक विश्लेषणात्मक वर्कफ़्लो के साथ जोड़ता है। + +**कार्यान्वयन**: +क्वेरी ट्रांसलेशन लेयर: ग्राफ क्वेरी → कॉलम क्वेरी +एक हाइब्रिड स्टोरेज रणनीति जो ग्राफ ऑपरेशंस और विश्लेषणात्मक वर्कलोड दोनों का समर्थन करती है। +दोनों प्रतिमानों में क्वेरी प्रदर्शन बनाए रखें। + +-- + +## आर्किटेक्चर प्रिंसिपल्स समरी + +1. **लचीलापन पहले**: एस.पी.ओ./आर.डी.एफ. मॉडल अधिकतम अनुकूलन क्षमता प्रदान करता है। +2. **एलएलएम अनुकूलन**: सभी डिज़ाइन निर्णयों पर एलएलएम इंटरैक्शन आवश्यकताओं पर विचार किया जाता है। +3. **सिमेंटिक दक्षता**: इष्टतम क्वेरी प्रदर्शन के लिए प्रत्यक्ष एम्बेडिंग-टू-नोड मैपिंग। +4. **व्यावहारिक स्केलेबिलिटी**: सही सटीकता को व्यावहारिक वितरित प्रसंस्करण के साथ संतुलित करें। +5. **इवेंट-ड्रिवन समन्वय**: पब-सब ढीला युग्मन और स्केलेबिलिटी को सक्षम करता है। +6. **एजेंट-फ्रेंडली**: जटिल, बहु-एजेंट प्रसंस्करण वर्कफ़्लो का समर्थन करें। +7. **विश्लेषणात्मक अनुकूलता**: व्यापक क्वेरी के लिए ग्राफ और कॉलम प्रतिमानों को जोड़ें। + +ये फाउंडेशन एक नॉलेज ग्राफ आर्किटेक्चर स्थापित करते हैं जो सैद्धांतिक कठोरता को व्यावहारिक स्केलेबिलिटी आवश्यकताओं के साथ संतुलित करता है, जो एलएलएम एकीकरण और वितरित प्रसंस्करण के लिए अनुकूलित है। + diff --git a/docs/tech-specs/architecture-principles.pt.md b/docs/tech-specs/architecture-principles.pt.md new file mode 100644 index 00000000..cdc097bc --- /dev/null +++ b/docs/tech-specs/architecture-principles.pt.md @@ -0,0 +1,106 @@ +# Arquitetura de Grafos de Conhecimento: Fundamentos + +## Fundamento 1: Modelo de Grafo Sujeito-Predicado-Objeto (SPO) +**Decisão**: Adotar SPO/RDF como o modelo central de representação de conhecimento + +**Justificativa**: +- Fornece máxima flexibilidade e interoperabilidade com tecnologias de grafos existentes +- Permite a tradução perfeita para outras linguagens de consulta de grafos (por exemplo, SPO → Cypher, mas não o contrário) +- Cria uma base que "desbloqueia muitas" capacidades subsequentes +- Suporta relacionamentos de nó para nó (SPO) e relacionamentos de nó para literal (RDF) + +**Implementação**: +- Estrutura de dados principal: `node → edge → {node | literal}` +- Manter a compatibilidade com os padrões RDF, ao mesmo tempo em que suporta operações SPO estendidas + +## Fundamento 2: Integração Nativa de Grafos de Conhecimento com LLMs +**Decisão**: Otimizar a estrutura e as operações do grafo de conhecimento para a interação com LLMs + +**Justificativa**: +- O caso de uso primário envolve LLMs interagindo com grafos de conhecimento +- As escolhas da tecnologia de grafos devem priorizar a compatibilidade com LLMs em vez de outras considerações +- Permite fluxos de trabalho de processamento de linguagem natural que aproveitam o conhecimento estruturado + +**Implementação**: +- Projetar esquemas de grafo que os LLMs possam entender e usar efetivamente +- Otimizar para padrões comuns de interação com LLMs + +## Fundamento 3: Navegação de Grafos Baseada em Incorporações +**Decisão**: Implementar um mapeamento direto de consultas de linguagem natural para nós de grafos por meio de incorporações + +**Justificativa**: +- Permite o caminho mais simples possível de uma consulta de PNL para a navegação no grafo +- Evita etapas complexas de geração de consultas intermediárias +- Fornece capacidades de pesquisa semântica eficientes dentro da estrutura do grafo + +**Implementação**: +- `NLP Query → Graph Embeddings → Graph Nodes` +- Manter representações de incorporação para todas as entidades do grafo +- Suporte para correspondência de similaridade semântica direta para a resolução de consultas + +## Fundamento 4: Resolução Distribuída de Entidades com Identificadores Determinísticos +**Decisão**: Suportar a extração de conhecimento paralela com identificação determinística de entidades (regra dos 80%) + +**Justificativa**: +- **Ideal**: A extração em um único processo com visibilidade completa do estado permite a resolução perfeita de entidades +- **Realidade**: Os requisitos de escalabilidade exigem capacidades de processamento paralelo +- **Compromisso**: Projetar para identificação determinística de entidades em processos distribuídos + +**Implementação**: +- Desenvolver mecanismos para gerar identificadores consistentes e exclusivos em diferentes extratores de conhecimento +- A mesma entidade mencionada em processos diferentes deve resolver para o mesmo identificador +- Reconhecer que ~20% dos casos extremos podem exigir modelos de processamento alternativos +- Projetar mecanismos de fallback para cenários complexos de resolução de entidades + +## Fundamento 5: Arquitetura Orientada a Eventos com Publicação-Subscrição +**Decisão**: Implementar um sistema de mensagens pub-sub para a coordenação do sistema + +**Justificativa**: +- Permite o acoplamento frouxo entre os componentes de extração, armazenamento e consulta de conhecimento +- Suporta atualizações e notificações em tempo real em todo o sistema +- Facilita fluxos de trabalho de processamento distribuídos e escaláveis + +**Implementação**: +- Coordenação orientada a mensagens entre os componentes do sistema +- Streams de eventos para atualizações de conhecimento, conclusão da extração e resultados de consultas + +## Fundamento 6: Comunicação de Agentes Reentrantes +**Decisão**: Suportar operações pub-sub reentrantes para o processamento baseado em agentes + +**Justificativa**: +- Permite fluxos de trabalho sofisticados de agentes, nos quais os agentes podem acionar e responder uns aos outros +- Suporta pipelines complexos de processamento de conhecimento de várias etapas +- Permite padrões de processamento recursivos e iterativos + +**Implementação**: +- O sistema pub-sub deve lidar com chamadas reentrantes com segurança +- Mecanismos de coordenação de agentes que evitam loops infinitos +- Suporte para orquestração de fluxos de trabalho de agentes + +## Fundamento 7: Integração com Armazenamento de Dados Colunares +**Decisão**: Garantir a compatibilidade das consultas com sistemas de armazenamento colunar. + +**Justificativa**: +- Permite consultas analíticas eficientes em grandes conjuntos de dados de conhecimento. +- Suporta casos de uso de inteligência de negócios e relatórios. +- Integra a representação de conhecimento baseada em grafos com fluxos de trabalho analíticos tradicionais. + +**Implementação**: +- Camada de tradução de consultas: Consultas de grafos → Consultas colunares. +- Estratégia de armazenamento híbrida que suporta tanto operações de grafos quanto cargas de trabalho analíticas. +- Manter o desempenho das consultas em ambos os paradigmas. + +--- + +## Resumo dos Princípios da Arquitetura + +1. **Flexibilidade em Primeiro Lugar**: O modelo SPO/RDF fornece a máxima adaptabilidade. +2. **Otimização para LLM**: Todas as decisões de design consideram os requisitos de interação com LLM. +3. **Eficiência Semântica**: Mapeamento direto de embeddings para nós para desempenho ideal da consulta. +4. **Escalabilidade Pragmática**: Equilibrar a precisão perfeita com o processamento distribuído prático. +5. **Coordenação Orientada a Eventos**: Pub-sub permite o acoplamento fraco e a escalabilidade. +6. **Compatível com Agentes**: Suporta fluxos de trabalho complexos de processamento multi-agentes. +7. **Compatibilidade Analítica**: Integra os paradigmas de grafos e colunares para consultas abrangentes. + +Essas bases estabelecem uma arquitetura de grafo de conhecimento que equilibra a rigidez teórica com os requisitos práticos de escalabilidade, otimizada para a integração com LLM e o processamento distribuído. + diff --git a/docs/tech-specs/architecture-principles.ru.md b/docs/tech-specs/architecture-principles.ru.md new file mode 100644 index 00000000..99613e4d --- /dev/null +++ b/docs/tech-specs/architecture-principles.ru.md @@ -0,0 +1,106 @@ +# Основы архитектуры графа знаний + +## Основа 1: Модель графа "Субъект-Предикат-Объект" (SPO) +**Решение**: Принять SPO/RDF в качестве основной модели представления знаний. + +**Обоснование**: +Обеспечивает максимальную гибкость и совместимость с существующими технологиями графов. +Позволяет беспрепятственно переводить в другие языки запросов к графам (например, SPO → Cypher, но не наоборот). +Создает основу, которая "открывает множество" возможностей для дальнейшей разработки. +Поддерживает как отношения между узлами (SPO), так и отношения между узлами и литералами (RDF). + +**Реализация**: +Основная структура данных: `node → edge → {node | literal}` +Поддерживать совместимость со стандартами RDF, одновременно поддерживая расширенные операции SPO. + +## Основа 2: Интеграция графа знаний, оптимизированная для LLM +**Решение**: Оптимизировать структуру и операции графа знаний для взаимодействия с LLM. + +**Обоснование**: +Основной сценарий использования включает взаимодействие LLM с графами знаний. +Выбор технологий графов должен отдавать приоритет совместимости с LLM, а не другим соображениям. +Обеспечивает потоки обработки естественного языка, использующие структурированные знания. + +**Реализация**: +Разрабатывать схемы графов, которые LLM могут эффективно использовать для рассуждений. +Оптимизировать для распространенных шаблонов взаимодействия LLM. + +## Основа 3: Навигация по графу на основе встраиваний +**Решение**: Реализовать прямое сопоставление между запросами на естественном языке и узлами графа с помощью встраиваний. + +**Обоснование**: +Обеспечивает самый простой путь от запроса на естественном языке к навигации по графу. +Избегает сложных промежуточных этапов генерации запросов. +Предоставляет возможности семантического поиска в структуре графа. + +**Реализация**: +`NLP Query → Graph Embeddings → Graph Nodes` +Поддерживать представления встраиваний для всех сущностей графа. +Поддерживать прямое семантическое сопоставление сходства для разрешения запросов. + +## Основа 4: Распределенное разрешение сущностей с детерминированными идентификаторами +**Решение**: Поддерживать параллельное извлечение знаний с детерминированной идентификацией сущностей (правило 80%). + +**Обоснование**: +**Идеально**: Извлечение в одном процессе с полной видимостью состояния обеспечивает идеальное разрешение сущностей. +**Реальность**: Требования к масштабируемости требуют возможностей параллельной обработки. +**Компромисс**: Разработать для детерминированной идентификации сущностей в распределенных процессах. + +**Реализация**: +Разработать механизмы для генерации согласованных, уникальных идентификаторов в различных инструментах извлечения знаний. +Одна и та же сущность, упомянутая в разных процессах, должна разрешаться в один и тот же идентификатор. +Признать, что ~20% крайних случаев могут потребовать альтернативных моделей обработки. +Разработать механизмы отката для сложных сценариев разрешения сущностей. + +## Основа 5: Архитектура, управляемая событиями, с публикацией и подпиской +**Решение**: Реализовать систему обмена сообщениями pub-sub для координации системы. + +**Обоснование**: +Обеспечивает слабую связанность между компонентами извлечения знаний, хранения и запросов. +Поддерживает обновления в режиме реального времени и уведомления по всей системе. +Облегчает масштабируемые, распределенные рабочие процессы. + +**Реализация**: +Координация между компонентами системы с помощью управляемых сообщениями. +Потоки событий для обновлений знаний, завершения извлечения и результатов запросов. + +## Основа 6: Взаимодействие агентов с возможностью повторного входа +**Решение**: Поддерживать операции pub-sub с возможностью повторного входа для обработки на основе агентов. + +**Обоснование**: +Позволяет создавать сложные рабочие процессы агентов, в которых агенты могут инициировать и реагировать друг на друга. +Поддерживает сложные, многоступенчатые конвейеры обработки знаний. +Позволяет использовать рекурсивные и итеративные шаблоны обработки. + +**Реализация**: +Система pub-sub должна безопасно обрабатывать вызовы с повторным входом. +Механизмы координации агентов, предотвращающие бесконечные циклы. +Поддержка оркестровки рабочих процессов агентов. + +## Основа 7: Интеграция с хранилищем данных в столбцовом формате +**Решение**: Обеспечить совместимость запросов с системами хранения данных в столбцовом формате. + +**Обоснование**: +Обеспечивает эффективные аналитические запросы к большим наборам данных знаний. +Поддерживает сценарии бизнес-аналитики и отчетности. +Объединяет представление знаний на основе графов с традиционными аналитическими рабочими процессами. + +**Реализация**: +Слой перевода запросов: Запросы графов → Запросы в столбцовом формате. +Гибридная стратегия хранения, поддерживающая как операции графов, так и аналитические рабочие нагрузки. +Поддерживать производительность запросов в обеих парадигмах. + +-- + +## Краткое изложение принципов архитектуры + +1. **Гибкость прежде всего**: Модель SPO/RDF обеспечивает максимальную адаптируемость. +2. **Оптимизация для LLM**: Все решения в области проектирования учитывают требования взаимодействия с LLM. +3. **Семантическая эффективность**: Прямое сопоставление встраиваний с узлами для оптимальной производительности запросов. +4. **Прагматическая масштабируемость**: Баланс между идеальной точностью и практическими возможностями распределенной обработки. +5. **Координация, управляемая событиями**: Pub-sub обеспечивает слабую связанность и масштабируемость. +6. **Поддержка агентов**: Поддержка сложных рабочих процессов, основанных на нескольких агентах. +7. **Совместимость с аналитикой**: Объединение парадигм графов и столбцов для всестороннего запроса. + +Эта архитектура графа знаний сочетает теоретическую строгость с практическими требованиями масштабируемости, оптимизированная для интеграции с LLM и распределенной обработки. + diff --git a/docs/tech-specs/architecture-principles.sw.md b/docs/tech-specs/architecture-principles.sw.md new file mode 100644 index 00000000..b7721c73 --- /dev/null +++ b/docs/tech-specs/architecture-principles.sw.md @@ -0,0 +1,106 @@ +# Msingi wa Usanifu wa Grafu ya Maarifa + +## Msingi wa 1: Mfumo wa Grafu wa Mada-Kitendawili-Jambo (SPO) +**Uamuzi**: Kubali SPO/RDF kama mfumo mkuu wa uwakilishi wa maarifa + +**Sababu**: +Hutoa uwezekano mwingi na utangamano na teknolojia za grafu zilizopo +Inawezesha tafsiri rahisi kwa lugha zingine za kuuliza grafu (e.g., SPO → Cypher, lakini si kinyume chake) +Huunda msingi ambao "unawezesha mengi" ya uwezo wa baadaye +Inasaidia uhusiano wa kutoka-kwenye-node (SPO) na uhusiano wa kutoka-kwenye-jambo (RDF) + +**Utendaji**: +Muundo mkuu wa data: `node → edge → {node | literal}` +Endelea utangamano na viwango vya RDF huku ukiunga mkono operesheni zilizopanuliwa za SPO + +## Msingi wa 2: Uunganishaji wa Asili wa Grafu ya Maarifa na LLM +**Uamuzi**: Boresha muundo na operesheni za grafu ya maarifa ili kuendana na mwingiliano wa LLM + +**Sababu**: +Matumizi kuu yanahusisha LLM zinazofanya kazi na grafu za maarifa +Chaguo za teknolojia za grafu lazima zipende utangamano wa LLM kuliko mambo mengine +Inawezesha mchakato wa usindikaji wa lugha ya asili ambao hutumia maarifa yaliyopangwa + +**Utendaji**: +Unda schema za grafu ambazo LLM zinaweza kuzielewa vizuri +Boresha kwa mifumo ya kawaida ya mwingiliano wa LLM + +## Msingi wa 3: Uramaji wa Grafu kwa Kutumia Uingizwaji +**Uamuzi**: Tengeneza uhusiano wa moja kwa moja kutoka maswali ya lugha ya asili hadi node za grafu kupitia uingizwaji + +**Sababu**: +Inawezesha njia rahisi iwezekanavyo kutoka swali la NLP hadi uramaji wa grafu +Inazuia hatua ngumu za kati za kuunda swali +Hutoa uwezo wa utafutaji wa kiufundi ndani ya muundo wa grafu + +**Utendaji**: +`NLP Query → Graph Embeddings → Graph Nodes` +Endelea uwakilishi wa uingizwaji kwa vyombo vyote vya grafu +Unga mlingano wa moja kwa moja wa kiufundi kwa utatuzi wa swali + +## Msingi wa 4: Utatuzi Ulio Msingi wa Vitambulisho vya Ufafu na Ufumbuzi Ulio Msingi wa Vitambulisho +**Uamuzi**: Unga uongezaji wa maarifa kwa usindikaji sambamba kwa kutumia utambulisho wa vitu vya ufafu (kanuni ya 80%) + +**Sababu**: +**Lengo**: Uongezaji wa mchakato mmoja kwa hali kamili unawezesha utatuzi kamili wa vitu +**Ukwereti**: Mahitaji ya uongezaji yanahitaji uwezo wa usindikaji sambamba +**Suluhisho la Kompromi**: Unda kwa utambulisho wa vitu vya ufafu katika mchakato uliogawanyika + +**Utendaji**: +Unda mitambo ya kuzalisha vitambulisho sawa na vya kipekee katika viboreshaji tofauti vya maarifa +Kitu kimoja kinachotajwa katika mchakato tofauti lazima kiwe na kitambulisho kimoja +Amini kwamba ~20% ya hali ngumu zinaweza kuhitaji modeli zingine za usindikaji +Unda mitambo ya dharura kwa hali ngumu za utatuzi wa vitu + +## Msingi wa 5: Usanifu Ulioendeshwa na Tukio na Uchukuzi-Ulisikilizaji +**Uamuzi**: Tengeneza mfumo wa ujumbe wa pub-sub kwa upangaji wa mfumo + +**Sababu**: +Inawezesha kuunganishwa kwa huru kati ya uongezaji wa maarifa, uhifadhi, na vipengele vya kuuliza +Inasaidia sasisho na arifa za wakati halisi katika mfumo +Inawezesha mchakato wa usindikaji uliogawanyika na unaoweza kupanuka + +**Utendaji**: +Uunganisho uliodumishwa na ujumbe kati ya vipengele vya mfumo +Mito ya matukio kwa sasisho za maarifa, kukamilika kwa uongezaji, na matokeo ya kuuliza + +## Msingi wa 6: Mawasiliano ya Wakala wa Kurejea +**Uamuzi**: Unga operesheni za pub-sub za kurejea kwa usindikaji wa wakala + +**Sababu**: +Inawezesha mchakato wa wakala wa hali ya juu ambapo wakala wanaweza kuchochea na kujibu kila mmoja +Inasaidia njia ngumu za usindikaji wa maarifa +Inaruhusu mifumo ya usindikaji ya kurudia na ya mara kwa mara + +**Utendaji**: +Mfumo wa pub-sub lazima uweze kushughulikia simu za kurejea kwa usalama +Mitambo ya upangaji wa wakala ambayo inazuia mzunguko usio na mwisho +Usaidizi wa upangaji wa mchakato wa wakala + +## Msingi wa 7: Uunganishaji wa Duka la Data ya Safu +**Uamuzi**: Hakikisha utangamano wa kuuliza na mifumo ya uhifadhi wa safu + +**Sababu**: +Inawezesha maswali ya uchambuzi ya ufanisi juu ya data kubwa ya maarifa +Inasaidia matumizi ya biashara ya ujasusi na ripoti +Huunganisha uwakilishi wa maarifa ya grafu na mchakato wa uchambuzi wa jadi + +**Utendaji**: +Safu ya tafsiri ya kuuliza: Maswali ya grafu → Maswali ya safu +Mkakati wa uhifadhi wa mchanganyiko unaounga mkono operesheni za grafu na mizigo ya uchambuzi +Endelea utendaji wa kuuliza katika pande zote + +-- + +## Muhtasari wa Kanuni za Usanifu + +1. **Uwezekano Kwanza**: Mfumo wa SPO hutoa uwezekano mwingi +2. **Uongezaji wa LLM**: Maamuzi yote ya usanifu yanafikiria mahitaji ya mwingiliano wa LLM +3. **Ufanisi wa Kiufundi**: Uramaji wa moja kwa moja wa uingizwaji hadi node kwa utendaji bora wa swali +4. **Uongezaji wa Kimapokeo**: Panga usahihi kamili na uwezo wa usindikaji uliogawanyika +5. **Usaidizi wa Vitambulisho**: Ufafu wa vitu na utatuzi wa vitu +6. **Mawasiliano ya Wakala**: Usaidizi wa mchakato wa wakala +7. **Uunganishaji wa Duka la Data**: Usaidizi wa maswali ya uchambuzi + +Misingi hizi huunda usanifu wa mfumo wa kujua ambao unachanganua umakini wa kinadharia na mahitaji ya utendakazi, ukiwa umeboreshwa kwa ajili ya ujumuishaji wa LLM na usindikaji ulioenelea. + diff --git a/docs/tech-specs/architecture-principles.tr.md b/docs/tech-specs/architecture-principles.tr.md new file mode 100644 index 00000000..716ce62e --- /dev/null +++ b/docs/tech-specs/architecture-principles.tr.md @@ -0,0 +1,106 @@ +# Bilgi Grafiği Mimarisi Temelleri + +## Temel 1: Özne-Yüklem-Nesne (ÖYY) Grafik Modeli +**Karar**: Çekirdek bilgi gösterim modeli olarak SPO/RDF'yi benimse + +**Gerekçe**: +- Mevcut grafik teknolojileriyle maksimum esneklik ve uyumluluk sağlar +- Diğer grafik sorgu dillerine (örneğin, SPO → Cypher, ancak tersi değil) sorunsuz çeviri sağlar +- "Birçok" sonraki yeteneği "açığa çıkaran" bir temel oluşturur +- Hem düğüm-düğüm ilişkilerini (ÖYY) hem de düğüm-literal ilişkilerini (RDF) destekler + +**Uygulama**: +- Temel veri yapısı: `node → edge → {node | literal}` +- RDF standartlarıyla uyumluluğu korurken, gelişmiş SPO işlemlerini destekler + +## Temel 2: LLM-Yerel Bilgi Grafiği Entegrasyonu +**Karar**: Bilgi grafiği yapısını ve işlemlerini LLM etkileşimi için optimize et + +**Gerekçe**: +- Birincil kullanım durumu, LLM'lerin bilgi grafikleriyle etkileşimini içerir +- Grafik teknolojisi seçimleri, diğer hususlara kıyasla LLM uyumluluğuna öncelik vermelidir +- Yapılandırılmış bilgiyi kullanan doğal dil işleme iş akışlarını sağlar + +**Uygulama**: +- LLM'lerin etkili bir şekilde akıl yürütebileceği grafik şemalarını tasarla +- Yaygın LLM etkileşim kalıpları için optimize et + +## Temel 3: Gömme Tabanlı Grafik Navigasyonu +**Karar**: Doğal dil sorgularını, gömmeler aracılığıyla doğrudan grafik düğümlerine eşleyin + +**Gerekçe**: +- NLP sorgusundan grafik navigasyonuna en basit yolu sağlar +- Karmaşık ara sorgu oluşturma adımlarından kaçının +- Grafik yapısı içinde verimli semantik arama yetenekleri sağlar + +**Uygulama**: +- `NLP Query → Graph Embeddings → Graph Nodes` +- Tüm grafik varlıkları için gömme gösterimlerini koru +- Sorgu çözümlemesi için doğrudan semantik benzerlik eşleştirmesini destekle + +## Temel 4: Dağıtılmış Varlık Çözümlemesi ve Belirleyici Tanımlayıcılar +**Karar**: Paralel bilgi çıkarma işlemini, deterministik varlık tanımlamasıyla (80% kuralı) destekle + +**Gerekçe**: +- **İdeal**: Tam durum görünürlüğü sağlayan tek işlem çıkarma, mükemmel varlık çözümlemesine olanak tanır +- **Gerçeklik**: Ölçeklenebilirlik gereksinimleri, paralel işleme yetenekleri gerektirir +- **Uzlaşma**: Dağıtılmış işlemler arasında deterministik varlık tanımlaması için tasarla + +**Uygulama**: +- Farklı bilgi çıkarıcılar arasında tutarlı, benzersiz tanımlayıcılar oluşturmak için mekanizmalar geliştir +- Farklı işlemlerde bahsedilen aynı varlık, aynı tanımlayıcıya çözümlenmelidir +- Yaklaşık olarak %20'lik bir oranın, alternatif işleme modelleri gerektirebilecek uç durumlara karşılık geldiğinin farkında olun +- Karmaşık varlık çözümleme senaryoları için yedek mekanizmalar tasarla + +## Temel 5: Yayın-Abonelik ile Olay Odaklı Mimari +**Karar**: Sistem koordinasyonu için bir yayın-abone mesajlaşma sistemi uygula + +**Gerekçe**: +- Bilgi çıkarma, depolama ve sorgu bileşenleri arasında gevşek bir bağlama olanak tanır +- Sistem genelinde gerçek zamanlı güncellemeleri ve bildirimleri destekler +- Ölçeklenebilir, dağıtılmış iş akışlarını kolaylaştırır + +**Uygulama**: +- Sistem bileşenleri arasındaki mesaj odaklı koordinasyon +- Bilgi güncellemeleri, çıkarma tamamlama ve sorgu sonuçları için olay akışları + +## Temel 6: Geri Çağrılabilir Ajan İletişimi +**Karar**: Ajan tabanlı işleme için geri çağrılabilir yayın-abone işlemlerini destekle + +**Gerekçe**: +- Ajanların birbirini tetikleyebildiği ve yanıtlayabildiği gelişmiş ajan iş akışlarına olanak tanır +- Karmaşık, çok aşamalı bilgi işleme boru hatlarını destekler +- Yinelemeli ve yinelemeli işleme kalıplarına izin verir + +**Uygulama**: +- Yayın-abone sistemi, geri çağrılabilir çağrıları güvenli bir şekilde işlemelidir +- Sonsuz döngüleri önleyen ajan koordinasyon mekanizmaları +- Ajan iş akışı orkestrasyonu desteği + +## Temel 7: Sütun Veri Depolama Entegrasyonu +**Karar**: Sorgu uyumluluğunun, sütunlu depolama sistemleriyle sağlanması. + +**Gerekçe**: +- Büyük bilgi veri kümeleri üzerinde verimli analitik sorgulara olanak tanır. +- İş zekası ve raporlama kullanım senaryolarını destekler. +- Grafik tabanlı bilgi gösterimini geleneksel analitik iş akışlarıyla birleştirir. + +**Uygulama**: +- Sorgu çevirme katmanı: Grafik sorguları → Sütunlu sorgular. +- Hem grafik işlemlerini hem de analitik iş yüklerini destekleyen hibrit depolama stratejisi. +- Her iki paradigma için de sorgu performansını koruyun. + +--- + +## Mimari İlkeler Özeti + +1. **Öncelikli Olarak Esneklik**: SPO/RDF modeli, maksimum uyarlanabilirlik sağlar. +2. **LLM Optimizasyonu**: Tüm tasarım kararları, LLM etkileşim gereksinimlerini dikkate alır. +3. **Anlamsal Verimlilik**: Optimum sorgu performansı için doğrudan gömülü-düğüm eşlemesi. +4. **Pratik Ölçeklenebilirlik**: Mükemmel doğruluğu, pratik dağıtılmış işleme ile dengeleyin. +5. **Olay Odaklı Koordinasyon**: Yayın-abone, gevşek bağlama ve ölçeklenebilirliğe olanak tanır. +6. **Ajan Dostu**: Karmaşık, çoklu ajan iş akışlarını destekler. +7. **Analitik Uyumluluk**: Kapsamlı sorgulama için grafik ve sütunlu paradigmaları birleştirir. + +Bu temeller, teorik titizliği pratik ölçeklenebilirlik gereksinimleriyle dengeleyen, LLM entegrasyonu ve dağıtılmış işleme için optimize edilmiş bir bilgi grafiği mimarisi oluşturur. + diff --git a/docs/tech-specs/architecture-principles.zh-cn.md b/docs/tech-specs/architecture-principles.zh-cn.md new file mode 100644 index 00000000..c115e1e1 --- /dev/null +++ b/docs/tech-specs/architecture-principles.zh-cn.md @@ -0,0 +1,106 @@ +# 知识图谱架构基础 + +## 基础 1:主谓宾 (SPO) 图模型 +**决策**: 采用 SPO/RDF 作为核心知识表示模型 + +**理由**: +提供最大的灵活性和与现有图技术的互操作性 +能够无缝转换为其他图查询语言 (例如,SPO → Cypher,反之则不行) +奠定基础,"解锁"许多下游功能 +支持节点到节点的关系 (SPO) 和节点到字面值关系 (RDF) + +**实现**: +核心数据结构: `node → edge → {node | literal}` +在支持扩展的 SPO 操作的同时,保持与 RDF 标准的兼容性 + +## 基础 2:原生于 LLM 的知识图谱集成 +**决策**: 优化知识图谱结构和操作,以实现与 LLM 的交互 + +**理由**: +主要用例涉及 LLM 与知识图谱的交互 +图技术选择必须优先考虑与 LLM 的兼容性,而不是其他考虑因素 +能够实现利用结构化知识的自然语言处理工作流程 + +**实现**: +设计 LLM 可以有效推理的图模式 +针对常见的 LLM 交互模式进行优化 + +## 基础 3:基于嵌入的图导航 +**决策**: 通过嵌入将自然语言查询直接映射到图节点 + +**理由**: +实现从 NLP 查询到图导航的最简单路径 +避免复杂的中间查询生成步骤 +提供图结构内部高效的语义搜索功能 + +**实现**: +`NLP Query → Graph Embeddings → Graph Nodes` +维护所有图实体的嵌入表示 +支持用于查询解析的直接语义相似性匹配 + +## 基础 4:分布式实体解析与确定性标识符 +**决策**: 支持并行知识提取,并使用确定性实体标识 (80% 规则) + +**理由**: +**理想**: 单进程提取,具有完整的状态可见性,可以实现完美的实体解析 +**现实**: 可伸缩性要求需要并行处理能力 +**折衷**: 设计用于在分布式进程中实现确定性实体标识 + +**实现**: +开发机制,以在不同的知识提取器中生成一致且唯一的标识符 +在不同的进程中提到的相同实体必须解析为相同的标识符 +承认约 20% 的边缘情况可能需要替代处理模型 +设计用于复杂实体解析场景的后备机制 + +## 基础 5:事件驱动架构与发布-订阅 +**决策**: 实现 pub-sub 消息系统,用于系统协调 + +**理由**: +允许知识提取、存储和查询组件之间的松散耦合 +支持实时更新和跨系统的通知 +促进可扩展的分布式处理工作流程 + +**实现**: +基于消息的系统组件协调 +事件流用于知识更新、提取完成和查询结果 + +## 基础 6:可重入代理通信 +**决策**: 支持用于基于代理的处理的可重入 pub-sub 操作 + +**理由**: +允许代理触发和响应彼此,从而实现复杂的代理工作流程 +支持复杂的多步骤知识处理管道 +允许递归和迭代处理模式 + +**实现**: +pub-sub 系统必须安全地处理可重入调用 +代理协调机制,防止无限循环 +支持代理工作流程编排 + +## 基础 7:列式数据存储集成 +**决策**: 确保查询与列式存储系统兼容 + +**理由**: +能够对大型知识数据集执行高效的分析查询 +支持商业智能和报告用例 +连接基于图的知识表示与传统的分析工作流程 + +**实现**: +查询转换层:图查询 → 列式查询 +混合存储策略,支持图操作和分析工作负载 +在这两种范例中,保持查询性能 + +-- + +## 架构原则摘要 + +1. **灵活性至上**: SPO/RDF 模型提供最大的适应性 +2. **LLM 优化**: 所有设计决策都考虑 LLM 交互要求 +3. **语义效率**: 直接的嵌入到节点映射,以实现最佳查询性能 +4. **务实的扩展性**: 在完美准确性和实际的分布式处理之间取得平衡 +5. **事件驱动协调**: pub-sub 实现松散耦合和可扩展性 +6. **代理友好**: 支持复杂的多代理处理工作流程 +7. **分析兼容性**: 连接图和列式范例,实现全面的查询 + +这些基础构建了一个知识图谱架构,该架构在理论严谨性和实际可扩展性之间取得了平衡,并针对 LLM 集成和分布式处理进行了优化。 + diff --git a/docs/tech-specs/cassandra-consolidation.ar.md b/docs/tech-specs/cassandra-consolidation.ar.md new file mode 100644 index 00000000..a4934c48 --- /dev/null +++ b/docs/tech-specs/cassandra-consolidation.ar.md @@ -0,0 +1,331 @@ +# مواصفات فنية: توحيد إعدادات Cassandra + +**الحالة:** مسودة +**المؤلف:** مساعد +**التاريخ:** 2024-09-03 + +## نظرة عامة + +تتناول هذه المواصفة عدم الاتساق في أسماء وأنماط إعدادات معلمات اتصال Cassandra عبر قاعدة بيانات TrustGraph. حاليًا، توجد مخططان مختلفان لتسمية المعلمات (`cassandra_*` مقابل `graph_*`)، مما يؤدي إلى الارتباك وتعقيد الصيانة. + +## بيان المشكلة + +تستخدم قاعدة البيانات حاليًا مجموعتين متميزتين من معلمات إعداد Cassandra: + +1. **وحدات المعرفة/التكوين/المكتبة** تستخدم: + `cassandra_host` (قائمة المضيفين) + `cassandra_user` + `cassandra_password` + +2. **وحدات الرسم البياني/التخزين** تستخدم: + `graph_host` (مضيف واحد، يتم تحويله أحيانًا إلى قائمة) + `graph_username` + `graph_password` + +3. **عرض غير متسق عبر سطر الأوامر**: + بعض المعالجات (مثل `kg-store`) لا تعرض إعدادات Cassandra كمعلمات سطر أوامر + تعرض معالجات أخرى هذه الإعدادات بأسماء وتنسيقات مختلفة + لا يعكس نص المساعدة القيم الافتراضية لمتغيرات البيئة + +تتصل كلتا مجموعتي المعلمات بنفس مجموعة Cassandra ولكن باتفاقيات تسمية مختلفة، مما يسبب: +ارتباك في التكوين للمستخدمين +زيادة العبء على الصيانة +توثيق غير متسق +احتمال حدوث سوء تكوين +عدم القدرة على تجاوز الإعدادات عبر سطر الأوامر في بعض المعالجات + +## الحل المقترح + +### 1. توحيد أسماء المعلمات + +ستستخدم جميع الوحدات أسماء معلمات متسقة `cassandra_*`: +`cassandra_host` - قائمة المضيفين (مخزنة داخليًا كقائمة) +`cassandra_username` - اسم المستخدم للمصادقة +`cassandra_password` - كلمة المرور للمصادقة + +### 2. معلمات سطر الأوامر + +يجب على جميع المعالجات عرض إعدادات تكوين Cassandra عبر معلمات سطر الأوامر: +`--cassandra-host` - قائمة مفصولة بفواصل من المضيفين +`--cassandra-username` - اسم المستخدم للمصادقة +`--cassandra-password` - كلمة المرور للمصادقة + +### 3. الاعتماد على متغيرات البيئة + +إذا لم يتم توفير معلمات سطر الأوامر بشكل صريح، فسيتحقق النظام من متغيرات البيئة: +`CASSANDRA_HOST` - قائمة مفصولة بفواصل من المضيفين +`CASSANDRA_USERNAME` - اسم المستخدم للمصادقة +`CASSANDRA_PASSWORD` - كلمة المرور للمصادقة + +### 4. القيم الافتراضية + +إذا لم يتم تحديد أي من معلمات سطر الأوامر أو متغيرات البيئة: +`cassandra_host` افتراضيًا إلى `["cassandra"]` +`cassandra_username` افتراضيًا إلى `None` (بدون مصادقة) +`cassandra_password` افتراضيًا إلى `None` (بدون مصادقة) + +### 5. متطلبات نص المساعدة + +يجب أن يعرض الإخراج `--help`: +إظهار قيم متغيرات البيئة كقيم افتراضية عند تعيينها +عدم عرض قيم كلمات المرور مطلقًا (إظهار `****` أو `` بدلاً من ذلك) +الإشارة بوضوح إلى ترتيب الحل في نص المساعدة + +مثال على إخراج المساعدة: +``` +--cassandra-host HOST + Cassandra host list, comma-separated (default: prod-cluster-1,prod-cluster-2) + [from CASSANDRA_HOST environment variable] + +--cassandra-username USERNAME + Cassandra username (default: cassandra_user) + [from CASSANDRA_USERNAME environment variable] + +--cassandra-password PASSWORD + Cassandra password (default: ) +``` + +## تفاصيل التنفيذ + +### ترتيب حل المعلمات + +لكل معلمة في Cassandra، سيكون ترتيب الحل كما يلي: +1. قيمة وسيط سطر الأوامر +2. متغير البيئة (`CASSANDRA_*`) +3. القيمة الافتراضية + +### معالجة معلمات المضيف + +المعلمة `cassandra_host`: +يقبل سطر الأوامر سلسلة مفصولة بفواصل: `--cassandra-host "host1,host2,host3"` +يقبل متغير البيئة سلسلة مفصولة بفواصل: `CASSANDRA_HOST="host1,host2,host3"` +يتم تخزينها دائمًا داخليًا كقائمة: `["host1", "host2", "host3"]` +مضيف واحد: `"localhost"` → يتم تحويله إلى `["localhost"]` +إذا كانت بالفعل قائمة: `["host1", "host2"]` → يتم استخدامها كما هي + +### منطق المصادقة + +سيتم استخدام المصادقة عندما يتم توفير كل من `cassandra_username` و `cassandra_password`: +```python +if cassandra_username and cassandra_password: + # Use SSL context and PlainTextAuthProvider +else: + # Connect without authentication +``` + +## الملفات المراد تعديلها + +### الوحدات التي تستخدم معلمات `graph_*` (يجب تغييرها): +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/rows/cassandra/write.py` +`trustgraph-flow/trustgraph/query/triples/cassandra/service.py` + +### الوحدات التي تستخدم معلمات `cassandra_*` (يجب تحديثها مع استخدام الإعدادات الافتراضية للبيئة): +`trustgraph-flow/trustgraph/tables/config.py` +`trustgraph-flow/trustgraph/tables/knowledge.py` +`trustgraph-flow/trustgraph/tables/library.py` +`trustgraph-flow/trustgraph/storage/knowledge/store.py` +`trustgraph-flow/trustgraph/cores/knowledge.py` +`trustgraph-flow/trustgraph/librarian/librarian.py` +`trustgraph-flow/trustgraph/librarian/service.py` +`trustgraph-flow/trustgraph/config/service/service.py` +`trustgraph-flow/trustgraph/cores/service.py` + +### ملفات الاختبار المراد تحديثها: +`tests/unit/test_cores/test_knowledge_manager.py` +`tests/unit/test_storage/test_triples_cassandra_storage.py` +`tests/unit/test_query/test_triples_cassandra_query.py` +`tests/integration/test_objects_cassandra_integration.py` + +## استراتيجية التنفيذ + +### المرحلة الأولى: إنشاء أداة مساعدة للإعدادات المشتركة +إنشاء دوال مساعدة لتوحيد إعدادات Cassandra عبر جميع المعالجات: + +```python +import os +import argparse + +def get_cassandra_defaults(): + """Get default values from environment variables or fallback.""" + return { + 'host': os.getenv('CASSANDRA_HOST', 'cassandra'), + 'username': os.getenv('CASSANDRA_USERNAME'), + 'password': os.getenv('CASSANDRA_PASSWORD') + } + +def add_cassandra_args(parser: argparse.ArgumentParser): + """ + Add standardized Cassandra arguments to an argument parser. + Shows environment variable values in help text. + """ + defaults = get_cassandra_defaults() + + # Format help text with env var indication + host_help = f"Cassandra host list, comma-separated (default: {defaults['host']})" + if 'CASSANDRA_HOST' in os.environ: + host_help += " [from CASSANDRA_HOST]" + + username_help = f"Cassandra username" + if defaults['username']: + username_help += f" (default: {defaults['username']})" + if 'CASSANDRA_USERNAME' in os.environ: + username_help += " [from CASSANDRA_USERNAME]" + + password_help = "Cassandra password" + if defaults['password']: + password_help += " (default: )" + if 'CASSANDRA_PASSWORD' in os.environ: + password_help += " [from CASSANDRA_PASSWORD]" + + parser.add_argument( + '--cassandra-host', + default=defaults['host'], + help=host_help + ) + + parser.add_argument( + '--cassandra-username', + default=defaults['username'], + help=username_help + ) + + parser.add_argument( + '--cassandra-password', + default=defaults['password'], + help=password_help + ) + +def resolve_cassandra_config(args) -> tuple[list[str], str|None, str|None]: + """ + Convert argparse args to Cassandra configuration. + + Returns: + tuple: (hosts_list, username, password) + """ + # Convert host string to list + if isinstance(args.cassandra_host, str): + hosts = [h.strip() for h in args.cassandra_host.split(',')] + else: + hosts = args.cassandra_host + + return hosts, args.cassandra_username, args.cassandra_password +``` + +### المرحلة الثانية: تحديث الوحدات باستخدام معلمات `graph_*` +1. تغيير أسماء المعلمات من `graph_*` إلى `cassandra_*` +2. استبدال طرق `add_args()` المخصصة بطرق `add_cassandra_args()` القياسية +3. استخدام الدوال المساعدة الشائعة للتكوين +4. تحديث سلاسل التوثيق + +مثال على التحويل: +```python +# OLD CODE +@staticmethod +def add_args(parser): + parser.add_argument( + '-g', '--graph-host', + default="localhost", + help=f'Graph host (default: localhost)' + ) + parser.add_argument( + '--graph-username', + default=None, + help=f'Cassandra username' + ) + +# NEW CODE +@staticmethod +def add_args(parser): + FlowProcessor.add_args(parser) + add_cassandra_args(parser) # Use standard helper +``` + +### المرحلة الثالثة: تحديث الوحدات باستخدام معلمات `cassandra_*` +1. إضافة دعم للوسائط الخاصة بسطر الأوامر في الحالات التي تفتقر إليها (مثل: `kg-store`) +2. استبدال تعريفات الوسائط الحالية بـ `add_cassandra_args()` +3. استخدام `resolve_cassandra_config()` لتحقيق التوافق +4. التأكد من معالجة متسقة لقائمة المضيفين + +### المرحلة الرابعة: تحديث الاختبارات والوثائق +1. تحديث جميع ملفات الاختبار لاستخدام أسماء المعلمات الجديدة +2. تحديث وثائق واجهة سطر الأوامر +3. تحديث وثائق واجهة برمجة التطبيقات +4. إضافة وثائق لمتغيرات البيئة + +## التوافق مع الإصدارات السابقة + +للحفاظ على التوافق مع الإصدارات السابقة أثناء الانتقال: + +1. **تحذيرات الإيقاف التدريجي** لمعلمات `graph_*` +2. **تسمية بديلة للمعلمات** - قبول الأسماء القديمة والجديدة في البداية +3. **نشر تدريجي** على مدار عدة إصدارات +4. **تحديثات الوثائق** مع دليل الترحيل + +مثال على كود التوافق مع الإصدارات السابقة: +```python +def __init__(self, **params): + # Handle deprecated graph_* parameters + if 'graph_host' in params: + warnings.warn("graph_host is deprecated, use cassandra_host", DeprecationWarning) + params.setdefault('cassandra_host', params.pop('graph_host')) + + if 'graph_username' in params: + warnings.warn("graph_username is deprecated, use cassandra_username", DeprecationWarning) + params.setdefault('cassandra_username', params.pop('graph_username')) + + # ... continue with standard resolution +``` + +## استراتيجية الاختبار + +1. **اختبارات الوحدة** لمنطق حل التكوين. +2. **اختبارات التكامل** مع مجموعات تكوين مختلفة. +3. **اختبارات متغيرات البيئة**. +4. **اختبارات التوافق مع الإصدارات السابقة** مع المعلمات التي تم إيقافها. +5. **اختبارات Docker Compose** مع متغيرات البيئة. + +## تحديثات التوثيق + +1. تحديث جميع وثائق أوامر واجهة سطر الأوامر. +2. تحديث وثائق واجهة برمجة التطبيقات. +3. إنشاء دليل ترحيل. +4. تحديث أمثلة Docker Compose. +5. تحديث وثائق مرجع التكوين. + +## المخاطر والتخفيف + +| المخاطر | التأثير | التخفيف | +|------|--------|------------| +| تغييرات تؤثر على المستخدمين | مرتفع | تطبيق فترة التوافق مع الإصدارات السابقة. | +| ارتباك في التكوين أثناء الانتقال | متوسط | توثيق واضح وتحذيرات إيقاف. | +| فشل الاختبارات | متوسط | تحديثات شاملة للاختبارات. | +| مشاكل في نشر Docker | مرتفع | تحديث جميع أمثلة Docker Compose. | + +## معايير النجاح + +[ ] تستخدم جميع الوحدات أسماء معلمات `cassandra_*` متسقة. +[ ] تعرض جميع المعالجات إعدادات Cassandra عبر وسيطات سطر الأوامر. +[ ] يعرض نص المساعدة الخاص بسطر الأوامر القيم الافتراضية لمتغيرات البيئة. +[ ] لا يتم عرض قيم كلمات المرور في نص المساعدة. +[ ] يعمل التراجع إلى متغيرات البيئة بشكل صحيح. +[ ] يتم التعامل مع `cassandra_host` باستمرار كقائمة داخليًا. +[ ] تم الحفاظ على التوافق مع الإصدارات السابقة لمدة إصدارين على الأقل. +[ ] تجتاز جميع الاختبارات مع نظام التكوين الجديد. +[ ] تم تحديث التوثيق بالكامل. +[ ] تعمل أمثلة Docker Compose مع متغيرات البيئة. + +## الجدول الزمني + +**الأسبوع 1:** تنفيذ أداة مساعدة شائعة للتكوين وتحديث وحدات `graph_*`. +**الأسبوع 2:** إضافة دعم لمتغيرات البيئة إلى وحدات `cassandra_*` الحالية. +**الأسبوع 3:** تحديث الاختبارات والتوثيق. +**الأسبوع 4:** اختبار التكامل وتصحيح الأخطاء. + +## اعتبارات مستقبلية + +ضع في اعتبارك توسيع هذا النمط ليشمل تكوينات قواعد بيانات أخرى (مثل Elasticsearch). +تنفيذ التحقق من صحة التكوين ورسائل خطأ أفضل. +إضافة دعم لتكوين تجميع الاتصالات لـ Cassandra. +ضع في اعتبارك إضافة دعم لملفات التكوين (ملفات .env). \ No newline at end of file diff --git a/docs/tech-specs/cassandra-consolidation.he.md b/docs/tech-specs/cassandra-consolidation.he.md new file mode 100644 index 00000000..19dc58a6 --- /dev/null +++ b/docs/tech-specs/cassandra-consolidation.he.md @@ -0,0 +1,331 @@ +# מפרט טכני: איחוד תצורת Cassandra + +**סטטוס:** טיוטה +**כותב:** עוזר +**תאריך:** 2024-09-03 + +## סקירה כללית + +מפרט זה עוסק בדפוסי שמות ותצורות לא עקביים עבור פרמטרי חיבור ל-Cassandra ברחבי בסיס הקוד של TrustGraph. כיום, קיימים שני סכימות שמות פרמטרים שונות (`cassandra_*` לעומת `graph_*`), מה שמוביל לבלבול ולמורכבות תחזוקה. + +## הצגת הבעיה + +בסיס הקוד משתמש כיום בשתי קבוצות נפרדות של פרמטרי תצורה של Cassandra: + +1. **מודולים של Knowledge/Config/Library** משתמשים: + `cassandra_host` (רשימת מארחים) + `cassandra_user` + `cassandra_password` + +2. **מודולים של Graph/Storage** משתמשים: + `graph_host` (מאריך יחיד, לעיתים מומר לרשימה) + `graph_username` + `graph_password` + +3. **חשיפה לא עקבית דרך שורת הפקודה**: + חלק מהמעבדים (לדוגמה, `kg-store`) אינם חושפים הגדרות Cassandra כארגומנטים של שורת הפקודה + מעבדים אחרים חושפים אותם עם שמות ופורמטים שונים + טקסט העזרה אינו משקף ערכי משתני סביבה ברירת מחדל + +שתי קבוצות הפרמטרים מתחברות לאותו кластер Cassandra, אך עם קונבנציות שמות שונות, מה שגורם ל: +בלבול בתצורת משתמשים +עומס תחזוקה מוגבר +תיעוד לא עקבי +פוטנציאל לטעות בתצורה +חוסר יכולת לשנות הגדרות דרך שורת הפקודה בחלק מהמעבדים + +## פתרון מוצע + +### 1. סטנדרטיזציה של שמות פרמטרים + +כל המודולים ישתמשו בשמות פרמטרים עקביים של `cassandra_*`: +`cassandra_host` - רשימת מארחים (מאוחסנת פנימית כרשימה) +`cassandra_username` - שם משתמש לאימות +`cassandra_password` - סיסמה לאימות + +### 2. ארגומנטים של שורת הפקודה + +כל המעבדים חייבים לחשוף את תצורת Cassandra דרך ארגומנטים של שורת הפקודה: +`--cassandra-host` - רשימה מופרדת בפסיקים של מארחים +`--cassandra-username` - שם משתמש לאימות +`--cassandra-password` - סיסמה לאימות + +### 3. חלופה של משתני סביבה + +אם לא סופקו פרמטרים של שורת הפקודה, המערכת תבדוק משתני סביבה: +`CASSANDRA_HOST` - רשימה מופרדת בפסיקים של מארחים +`CASSANDRA_USERNAME` - שם משתמש לאימות +`CASSANDRA_PASSWORD` - סיסמה לאימות + +### 4. ערכי ברירת מחדל + +אם לא צוינו פרמטרים של שורת פקודה ולא משתני סביבה: +`cassandra_host` ברירת המחדל היא `["cassandra"]` +`cassandra_username` ברירת המחדל היא `None` (ללא אימות) +`cassandra_password` ברירת המחדל היא `None` (ללא אימות) + +### 5. דרישות טקסט עזרה + +הפלט של `--help` חייב: +להציג ערכי משתני סביבה כברירות מחדל כאשר הם מוגדרים +לעולם לא להציג ערכי סיסמה (להציג `****` או `` במקום) +לציין בבירור את סדר הפתרון בטקסט העזרה + +דוגמה לפלט עזרה: +``` +--cassandra-host HOST + Cassandra host list, comma-separated (default: prod-cluster-1,prod-cluster-2) + [from CASSANDRA_HOST environment variable] + +--cassandra-username USERNAME + Cassandra username (default: cassandra_user) + [from CASSANDRA_USERNAME environment variable] + +--cassandra-password PASSWORD + Cassandra password (default: ) +``` + +## פרטי יישום + +### סדר פתרון פרמטרים + +עבור כל פרמטר של Cassandra, סדר הפתרון יהיה: +1. ערך ארגומנט שורת הפקודה +2. משתנה סביבה (`CASSANDRA_*`) +3. ערך ברירת מחדל + +### טיפול בפרמטרים של מארחים + +הפרמטר `cassandra_host`: +שורת הפקודה מקבלת מחרוזת מופרדת בפסיקים: `--cassandra-host "host1,host2,host3"` +משתנה סביבה מקבל מחרוזת מופרדת בפסיקים: `CASSANDRA_HOST="host1,host2,host3"` +באופן פנימי תמיד מאוחסן כרשימה: `["host1", "host2", "host3"]` +מארח בודד: `"localhost"` → מומר ל-`["localhost"]` +כבר רשימה: `["host1", "host2"]` → משמש כפי שהוא + +### לוגיקת אימות + +אימות ישמש כאשר גם `cassandra_username` וגם `cassandra_password` מסופקים: +```python +if cassandra_username and cassandra_password: + # Use SSL context and PlainTextAuthProvider +else: + # Connect without authentication +``` + +## קבצים שיש לשנות + +### מודולים המשתמשים בפרמטרים `graph_*` (שיש לשנות): +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/rows/cassandra/write.py` +`trustgraph-flow/trustgraph/query/triples/cassandra/service.py` + +### מודולים המשתמשים בפרמטרים `cassandra_*` (שיש לעדכן עם אפשרות חלופה): +`trustgraph-flow/trustgraph/tables/config.py` +`trustgraph-flow/trustgraph/tables/knowledge.py` +`trustgraph-flow/trustgraph/tables/library.py` +`trustgraph-flow/trustgraph/storage/knowledge/store.py` +`trustgraph-flow/trustgraph/cores/knowledge.py` +`trustgraph-flow/trustgraph/librarian/librarian.py` +`trustgraph-flow/trustgraph/librarian/service.py` +`trustgraph-flow/trustgraph/config/service/service.py` +`trustgraph-flow/trustgraph/cores/service.py` + +### קבצי בדיקה שיש לעדכן: +`tests/unit/test_cores/test_knowledge_manager.py` +`tests/unit/test_storage/test_triples_cassandra_storage.py` +`tests/unit/test_query/test_triples_cassandra_query.py` +`tests/integration/test_objects_cassandra_integration.py` + +## אסטרטגיית יישום + +### שלב 1: יצירת כלי עזר להגדרות משותפות +צור פונקציות עזר לסטנדרטיזציה של הגדרות Cassandra בכל המעבדים: + +```python +import os +import argparse + +def get_cassandra_defaults(): + """Get default values from environment variables or fallback.""" + return { + 'host': os.getenv('CASSANDRA_HOST', 'cassandra'), + 'username': os.getenv('CASSANDRA_USERNAME'), + 'password': os.getenv('CASSANDRA_PASSWORD') + } + +def add_cassandra_args(parser: argparse.ArgumentParser): + """ + Add standardized Cassandra arguments to an argument parser. + Shows environment variable values in help text. + """ + defaults = get_cassandra_defaults() + + # Format help text with env var indication + host_help = f"Cassandra host list, comma-separated (default: {defaults['host']})" + if 'CASSANDRA_HOST' in os.environ: + host_help += " [from CASSANDRA_HOST]" + + username_help = f"Cassandra username" + if defaults['username']: + username_help += f" (default: {defaults['username']})" + if 'CASSANDRA_USERNAME' in os.environ: + username_help += " [from CASSANDRA_USERNAME]" + + password_help = "Cassandra password" + if defaults['password']: + password_help += " (default: )" + if 'CASSANDRA_PASSWORD' in os.environ: + password_help += " [from CASSANDRA_PASSWORD]" + + parser.add_argument( + '--cassandra-host', + default=defaults['host'], + help=host_help + ) + + parser.add_argument( + '--cassandra-username', + default=defaults['username'], + help=username_help + ) + + parser.add_argument( + '--cassandra-password', + default=defaults['password'], + help=password_help + ) + +def resolve_cassandra_config(args) -> tuple[list[str], str|None, str|None]: + """ + Convert argparse args to Cassandra configuration. + + Returns: + tuple: (hosts_list, username, password) + """ + # Convert host string to list + if isinstance(args.cassandra_host, str): + hosts = [h.strip() for h in args.cassandra_host.split(',')] + else: + hosts = args.cassandra_host + + return hosts, args.cassandra_username, args.cassandra_password +``` + +### שלב 2: עדכון מודולים באמצעות פרמטרים `graph_*` +1. שנה שמות הפרמטרים מ-`graph_*` ל-`cassandra_*` +2. החלף שיטות `add_args()` מותאמות אישית בשיטות `add_cassandra_args()` סטנדרטיות +3. השתמש בפונקציות העזר לתצורה נפוצות +4. עדכן מחרוזות תיעוד + +דוגמה לטרנספורמציה: +```python +# OLD CODE +@staticmethod +def add_args(parser): + parser.add_argument( + '-g', '--graph-host', + default="localhost", + help=f'Graph host (default: localhost)' + ) + parser.add_argument( + '--graph-username', + default=None, + help=f'Cassandra username' + ) + +# NEW CODE +@staticmethod +def add_args(parser): + FlowProcessor.add_args(parser) + add_cassandra_args(parser) # Use standard helper +``` + +### שלב 3: עדכון מודולים באמצעות פרמטרים `cassandra_*` +1. הוספת תמיכה בארגומנטים משורת הפקודה היכן שחסרים (לדוגמה, `kg-store`) +2. החלפת הגדרות ארגומנטים קיימות ב-`add_cassandra_args()` +3. שימוש ב-`resolve_cassandra_config()` עבור פתרון עקבי +4. הבטחת טיפול עקבי ברשימת השרתים + +### שלב 4: עדכון בדיקות ותיעוד +1. עדכון כל קבצי הבדיקה לשימוש בשמות פרמטרים חדשים +2. עדכון תיעוד שורת הפקודה (CLI) +3. עדכון תיעוד API +4. הוספת תיעוד עבור משתני סביבה + +## תאימות לאחור + +על מנת לשמור על תאימות לאחור במהלך המעבר: + +1. **אזהרות הפסקה** עבור פרמטרים `graph_*` +2. **כינוי פרמטרים** - קבלת שמות ישנים וחדשים בתחילה +3. **פריסה מדורגת** על פני מספר גרסאות +4. **עדכוני תיעוד** עם מדריך מעבר + +דוגמה לקוד תאימות לאחור: +```python +def __init__(self, **params): + # Handle deprecated graph_* parameters + if 'graph_host' in params: + warnings.warn("graph_host is deprecated, use cassandra_host", DeprecationWarning) + params.setdefault('cassandra_host', params.pop('graph_host')) + + if 'graph_username' in params: + warnings.warn("graph_username is deprecated, use cassandra_username", DeprecationWarning) + params.setdefault('cassandra_username', params.pop('graph_username')) + + # ... continue with standard resolution +``` + +## אסטרטגיית בדיקות + +1. **בדיקות יחידה** עבור לוגיקת פתרון תצורה +2. **בדיקות אינטגרציה** עם שילובים שונים של תצורות +3. **בדיקות משתני סביבה** +4. **בדיקות תאימות לאחור** עם פרמטרים מיושנים +5. **בדיקות Docker Compose** עם משתני סביבה + +## עדכוני תיעוד + +1. עדכון כל התיעוד של פקודות שורת הפקודה +2. עדכון תיעוד API +3. יצירת מדריך מעבר +4. עדכון דוגמאות Docker Compose +5. עדכון תיעוד הפניה לתצורה + +## סיכונים ודרכי התמודדות + +| סיכון | השפעה | דרך התמודדות | +|------|--------|------------| +| שינויים שעלולים לפגוע במשתמשים | גבוהה | יישום תקופת תאימות לאחור | +| בלבול בתצורה במהלך המעבר | בינונית | תיעוד ברור ואזהרות על הפסקה | +| כשלים בבדיקות | בינונית | עדכוני בדיקות מקיפים | +| בעיות בפריסת Docker | גבוהה | עדכון כל דוגמאות Docker Compose | + +## קריטריוני הצלחה + +[ ] כל המודולים משתמשים בשמות פרמטרים אחידים `cassandra_*` +[ ] כל המעבדים חושפים הגדרות Cassandra באמצעות ארגומנטים של שורת הפקודה +[ ] טקסט העזרה של שורת הפקודה מציג ערכי ברירת מחדל של משתני סביבה +[ ] ערכי סיסמה לעולם אינם מוצגים בטקסט העזרה +[ ] מנגנון החלפה למשתני סביבה פועל כהלכה +[ ] `cassandra_host` מטופל באופן עקבי כרשימה באופן פנימי +[ ] תאימות לאחור נשמרת לפחות עבור 2 גרסאות +[ ] כל הבדיקות עוברות עם מערכת התצורה החדשה +[ ] התיעוד מעודכן במלואו +[ ] דוגמאות Docker Compose עובדות עם משתני סביבה + +## ציר זמן + +**שבוע 1:** יישום עזר תצורה משותף ועדכון מודולי `graph_*` +**שבוע 2:** הוספת תמיכה במשתני סביבה למודולי `cassandra_*` קיימים +**שבוע 3:** עדכון בדיקות ותיעוד +**שבוע 4:** בדיקות אינטגרציה ותיקון באגים + +## שיקולים עתידיים + +שקול להרחיב את התבנית הזו לתצורות מסדי נתונים אחרות (לדוגמה, Elasticsearch) +יישום אימות תצורה והודעות שגיאה טובות יותר +הוספת תמיכה בתצורת חיבור בריכת חיבורים של Cassandra +שקול להוסיף תמיכה בקבצי תצורה (.env files) \ No newline at end of file diff --git a/docs/tech-specs/cassandra-consolidation.hi.md b/docs/tech-specs/cassandra-consolidation.hi.md new file mode 100644 index 00000000..5a8f49df --- /dev/null +++ b/docs/tech-specs/cassandra-consolidation.hi.md @@ -0,0 +1,331 @@ +# तकनीकी विनिर्देश: कैसेंड्रा कॉन्फ़िगरेशन समेकन + +**स्थिति:** मसौदा +**लेखक:** सहायक +**तिथि:** 2024-09-03 + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ कोडबेस में कैसेंड्रा कनेक्शन मापदंडों के लिए असंगत नामकरण और कॉन्फ़िगरेशन पैटर्न को संबोधित करता है। वर्तमान में, दो अलग-अलग पैरामीटर नामकरण योजनाएं मौजूद हैं (`cassandra_*` बनाम `graph_*`), जिससे भ्रम और रखरखाव जटिलता होती है। + +## समस्या विवरण + +कोडबेस वर्तमान में कैसेंड्रा कॉन्फ़िगरेशन मापदंडों के दो अलग-अलग सेट का उपयोग करता है: + +1. **ज्ञान/कॉन्फ़िग/लाइब्रेरी मॉड्यूल** निम्नलिखित का उपयोग करते हैं: + `cassandra_host` (होस्ट की सूची) + `cassandra_user` + `cassandra_password` + +2. **ग्राफ/भंडारण मॉड्यूल** निम्नलिखित का उपयोग करते हैं: + `graph_host` (एकल होस्ट, कभी-कभी सूची में परिवर्तित) + `graph_username` + `graph_password` + +3. **असंगत कमांड-लाइन एक्सपोजर**: + कुछ प्रोसेसर (जैसे, `kg-store`) कैसेंड्रा सेटिंग्स को कमांड-लाइन तर्कों के रूप में उजागर नहीं करते हैं + अन्य प्रोसेसर उन्हें अलग-अलग नामों और प्रारूपों के साथ उजागर करते हैं + सहायता पाठ पर्यावरण चर डिफ़ॉल्ट को प्रतिबिंबित नहीं करता है + +दोनों पैरामीटर सेट एक ही कैसेंड्रा क्लस्टर से जुड़ते हैं, लेकिन अलग-अलग नामकरण सम्मेलनों के साथ, जिससे: +उपयोगकर्ताओं के लिए कॉन्फ़िगरेशन भ्रम +रखरखाव का बढ़ता बोझ +असंगत प्रलेखन +गलत कॉन्फ़िगरेशन की संभावना +कुछ प्रोसेसर में कमांड-लाइन के माध्यम से सेटिंग्स को ओवरराइड करने में असमर्थता + +## प्रस्तावित समाधान + +### 1. पैरामीटर नामों का मानकीकरण + +सभी मॉड्यूल सुसंगत `cassandra_*` पैरामीटर नामों का उपयोग करेंगे: +`cassandra_host` - होस्ट की सूची (आंतरिक रूप से सूची के रूप में संग्रहीत) +`cassandra_username` - प्रमाणीकरण के लिए उपयोगकर्ता नाम +`cassandra_password` - प्रमाणीकरण के लिए पासवर्ड + +### 2. कमांड-लाइन तर्क + +सभी प्रोसेसर को कैसेंड्रा कॉन्फ़िगरेशन को कमांड-लाइन तर्कों के माध्यम से उजागर करना होगा: +`--cassandra-host` - होस्ट की अल्पविराम-विभाजित सूची +`--cassandra-username` - प्रमाणीकरण के लिए उपयोगकर्ता नाम +`--cassandra-password` - प्रमाणीकरण के लिए पासवर्ड + +### 3. पर्यावरण चर बैकअप + +यदि कमांड-लाइन पैरामीटर स्पष्ट रूप से प्रदान नहीं किए जाते हैं, तो सिस्टम पर्यावरण चर की जांच करेगा: +`CASSANDRA_HOST` - होस्ट की अल्पविराम-विभाजित सूची +`CASSANDRA_USERNAME` - प्रमाणीकरण के लिए उपयोगकर्ता नाम +`CASSANDRA_PASSWORD` - प्रमाणीकरण के लिए पासवर्ड + +### 4. डिफ़ॉल्ट मान + +यदि न तो कमांड-लाइन पैरामीटर और न ही पर्यावरण चर निर्दिष्ट हैं: +`cassandra_host` डिफ़ॉल्ट रूप से `["cassandra"]` है +`cassandra_username` डिफ़ॉल्ट रूप से `None` है (कोई प्रमाणीकरण नहीं) +`cassandra_password` डिफ़ॉल्ट रूप से `None` है (कोई प्रमाणीकरण नहीं) + +### 5. सहायता पाठ आवश्यकताएँ + +`--help` आउटपुट को: +जब सेट किया गया हो तो पर्यावरण चर मानों को डिफ़ॉल्ट के रूप में दिखाना चाहिए +पासवर्ड मानों को कभी भी प्रदर्शित नहीं करना चाहिए (इसके बजाय `****` या `` दिखाएं) +सहायता पाठ में समाधान क्रम को स्पष्ट रूप से इंगित करना चाहिए + +उदाहरण सहायता आउटपुट: +``` +--cassandra-host HOST + Cassandra host list, comma-separated (default: prod-cluster-1,prod-cluster-2) + [from CASSANDRA_HOST environment variable] + +--cassandra-username USERNAME + Cassandra username (default: cassandra_user) + [from CASSANDRA_USERNAME environment variable] + +--cassandra-password PASSWORD + Cassandra password (default: ) +``` + +## कार्यान्वयन विवरण + +### पैरामीटर समाधान का क्रम + +प्रत्येक कैसेंड्रा पैरामीटर के लिए, समाधान का क्रम इस प्रकार होगा: +1. कमांड-लाइन तर्क मान +2. पर्यावरण चर (`CASSANDRA_*`) +3. डिफ़ॉल्ट मान + +### होस्ट पैरामीटर हैंडलिंग + +`cassandra_host` पैरामीटर: +कमांड-लाइन अल्पविराम-विभाजित स्ट्रिंग स्वीकार करता है: `--cassandra-host "host1,host2,host3"` +पर्यावरण चर अल्पविराम-विभाजित स्ट्रिंग स्वीकार करता है: `CASSANDRA_HOST="host1,host2,host3"` +आंतरिक रूप से हमेशा सूची के रूप में संग्रहीत किया जाता है: `["host1", "host2", "host3"]` +एकल होस्ट: `"localhost"` → `["localhost"]` में परिवर्तित +पहले से ही एक सूची: `["host1", "host2"]` → जैसा है उपयोग किया जाता है + +### प्रमाणीकरण तर्क + +प्रमाणीकरण का उपयोग तब किया जाएगा जब `cassandra_username` और `cassandra_password` दोनों प्रदान किए जाते हैं: +```python +if cassandra_username and cassandra_password: + # Use SSL context and PlainTextAuthProvider +else: + # Connect without authentication +``` + +## संशोधित करने योग्य फ़ाइलें + +### `graph_*` पैरामीटर का उपयोग करने वाले मॉड्यूल (जिन्हें बदला जाना है): +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/rows/cassandra/write.py` +`trustgraph-flow/trustgraph/query/triples/cassandra/service.py` + +### `cassandra_*` पैरामीटर का उपयोग करने वाले मॉड्यूल (जिन्हें पर्यावरण बैकअप के साथ अपडेट किया जाना है): +`trustgraph-flow/trustgraph/tables/config.py` +`trustgraph-flow/trustgraph/tables/knowledge.py` +`trustgraph-flow/trustgraph/tables/library.py` +`trustgraph-flow/trustgraph/storage/knowledge/store.py` +`trustgraph-flow/trustgraph/cores/knowledge.py` +`trustgraph-flow/trustgraph/librarian/librarian.py` +`trustgraph-flow/trustgraph/librarian/service.py` +`trustgraph-flow/trustgraph/config/service/service.py` +`trustgraph-flow/trustgraph/cores/service.py` + +### अपडेट करने योग्य परीक्षण फ़ाइलें: +`tests/unit/test_cores/test_knowledge_manager.py` +`tests/unit/test_storage/test_triples_cassandra_storage.py` +`tests/unit/test_query/test_triples_cassandra_query.py` +`tests/integration/test_objects_cassandra_integration.py` + +## कार्यान्वयन रणनीति + +### चरण 1: सामान्य कॉन्फ़िगरेशन हेल्पर बनाएं +सभी प्रोसेसरों में कैसेंड्रा कॉन्फ़िगरेशन को मानकीकृत करने के लिए उपयोगिता फ़ंक्शन बनाएं: + +```python +import os +import argparse + +def get_cassandra_defaults(): + """Get default values from environment variables or fallback.""" + return { + 'host': os.getenv('CASSANDRA_HOST', 'cassandra'), + 'username': os.getenv('CASSANDRA_USERNAME'), + 'password': os.getenv('CASSANDRA_PASSWORD') + } + +def add_cassandra_args(parser: argparse.ArgumentParser): + """ + Add standardized Cassandra arguments to an argument parser. + Shows environment variable values in help text. + """ + defaults = get_cassandra_defaults() + + # Format help text with env var indication + host_help = f"Cassandra host list, comma-separated (default: {defaults['host']})" + if 'CASSANDRA_HOST' in os.environ: + host_help += " [from CASSANDRA_HOST]" + + username_help = f"Cassandra username" + if defaults['username']: + username_help += f" (default: {defaults['username']})" + if 'CASSANDRA_USERNAME' in os.environ: + username_help += " [from CASSANDRA_USERNAME]" + + password_help = "Cassandra password" + if defaults['password']: + password_help += " (default: )" + if 'CASSANDRA_PASSWORD' in os.environ: + password_help += " [from CASSANDRA_PASSWORD]" + + parser.add_argument( + '--cassandra-host', + default=defaults['host'], + help=host_help + ) + + parser.add_argument( + '--cassandra-username', + default=defaults['username'], + help=username_help + ) + + parser.add_argument( + '--cassandra-password', + default=defaults['password'], + help=password_help + ) + +def resolve_cassandra_config(args) -> tuple[list[str], str|None, str|None]: + """ + Convert argparse args to Cassandra configuration. + + Returns: + tuple: (hosts_list, username, password) + """ + # Convert host string to list + if isinstance(args.cassandra_host, str): + hosts = [h.strip() for h in args.cassandra_host.split(',')] + else: + hosts = args.cassandra_host + + return hosts, args.cassandra_username, args.cassandra_password +``` + +### चरण 2: `graph_*` पैरामीटर का उपयोग करके मॉड्यूल को अपडेट करें +1. पैरामीटर नामों को `graph_*` से `cassandra_*` में बदलें +2. कस्टम `add_args()` विधियों को मानकीकृत `add_cassandra_args()` से बदलें +3. सामान्य कॉन्फ़िगरेशन सहायक फ़ंक्शन का उपयोग करें +4. दस्तावेज़ स्ट्रिंग को अपडेट करें + +उदाहरण परिवर्तन: +```python +# OLD CODE +@staticmethod +def add_args(parser): + parser.add_argument( + '-g', '--graph-host', + default="localhost", + help=f'Graph host (default: localhost)' + ) + parser.add_argument( + '--graph-username', + default=None, + help=f'Cassandra username' + ) + +# NEW CODE +@staticmethod +def add_args(parser): + FlowProcessor.add_args(parser) + add_cassandra_args(parser) # Use standard helper +``` + +### चरण 3: `cassandra_*` पैरामीटर का उपयोग करके मॉड्यूल को अपडेट करें +1. उन स्थानों पर कमांड-लाइन तर्क समर्थन जोड़ें जहां यह गायब है (उदाहरण के लिए, `kg-store`) +2. मौजूदा तर्क परिभाषाओं को `add_cassandra_args()` से बदलें +3. सुसंगत समाधान के लिए `resolve_cassandra_config()` का उपयोग करें +4. सुसंगत होस्ट सूची प्रबंधन सुनिश्चित करें + +### चरण 4: परीक्षण और दस्तावेज़ को अपडेट करें +1. सभी परीक्षण फ़ाइलों को नए पैरामीटर नामों का उपयोग करने के लिए अपडेट करें +2. CLI दस्तावेज़ को अपडेट करें +3. API दस्तावेज़ को अपडेट करें +4. पर्यावरण चर दस्तावेज़ जोड़ें + +## पिछली अनुकूलता + +संक्रमण के दौरान पिछली अनुकूलता बनाए रखने के लिए: + +1. `graph_*` पैरामीटर के लिए **अवरोधन चेतावनी** +2. **पैरामीटर उपनाम** - शुरू में पुराने और नए दोनों नामों को स्वीकार करें +3. कई रिलीज़ में **चरणबद्ध कार्यान्वयन** +4. माइग्रेशन गाइड के साथ **दस्तावेज़ अपडेट** + +पिछली अनुकूलता कोड का उदाहरण: +```python +def __init__(self, **params): + # Handle deprecated graph_* parameters + if 'graph_host' in params: + warnings.warn("graph_host is deprecated, use cassandra_host", DeprecationWarning) + params.setdefault('cassandra_host', params.pop('graph_host')) + + if 'graph_username' in params: + warnings.warn("graph_username is deprecated, use cassandra_username", DeprecationWarning) + params.setdefault('cassandra_username', params.pop('graph_username')) + + # ... continue with standard resolution +``` + +## परीक्षण रणनीति + +1. **यूनिट परीक्षण** कॉन्फ़िगरेशन रिज़ॉल्यूशन लॉजिक के लिए +2. विभिन्न कॉन्फ़िगरेशन संयोजनों के साथ **एकीकरण परीक्षण** +3. **पर्यावरण चर परीक्षण** +4. **पिछड़ा संगतता परीक्षण** अप्रचलित मापदंडों के साथ +5. **डॉकर कंपोज़ परीक्षण** पर्यावरण चर के साथ + +## दस्तावेज़ अपडेट + +1. सभी CLI कमांड दस्तावेज़ों को अपडेट करें +2. API दस्तावेज़ों को अपडेट करें +3. माइग्रेशन गाइड बनाएं +4. डॉकर कंपोज़ उदाहरणों को अपडेट करें +5. कॉन्फ़िगरेशन संदर्भ दस्तावेज़ को अपडेट करें + +## जोखिम और निवारण + +| जोखिम | प्रभाव | निवारण | +|------|--------|------------| +| उपयोगकर्ताओं के लिए ब्रेकिंग परिवर्तन | उच्च | पिछड़े संगतता अवधि लागू करें | +| संक्रमण के दौरान कॉन्फ़िगरेशन भ्रम | मध्यम | स्पष्ट दस्तावेज़ और अवमूल्यन चेतावनियाँ | +| परीक्षण विफलताएँ | मध्यम | व्यापक परीक्षण अपडेट | +| डॉकर परिनियोजन मुद्दे | उच्च | सभी डॉकर कंपोज़ उदाहरणों को अपडेट करें | + +## सफलता मानदंड + +[ ] सभी मॉड्यूल सुसंगत `cassandra_*` पैरामीटर नामों का उपयोग करते हैं +[ ] सभी प्रोसेसर कमांड-लाइन तर्कों के माध्यम से कैसेंड्रा सेटिंग्स को उजागर करते हैं +[ ] कमांड-लाइन सहायता पाठ पर्यावरण चर डिफ़ॉल्ट दिखाता है +[ ] पासवर्ड मान कभी भी सहायता पाठ में प्रदर्शित नहीं होते हैं +[ ] पर्यावरण चर बैकअप सही ढंग से काम करता है +[ ] `cassandra_host` को आंतरिक रूप से लगातार एक सूची के रूप में संभाला जाता है +[ ] कम से कम 2 रिलीज़ के लिए पिछड़े संगतता बनाए रखी जाती है +[ ] सभी परीक्षण नए कॉन्फ़िगरेशन सिस्टम के साथ पास होते हैं +[ ] दस्तावेज़ पूरी तरह से अपडेट किया गया है +[ ] डॉकर कंपोज़ उदाहरण पर्यावरण चर के साथ काम करते हैं + +## समयरेखा + +**सप्ताह 1:** सामान्य कॉन्फ़िगरेशन हेल्पर लागू करें और `graph_*` मॉड्यूल को अपडेट करें +**सप्ताह 2:** मौजूदा `cassandra_*` मॉड्यूल में पर्यावरण चर समर्थन जोड़ें +**सप्ताह 3:** परीक्षण और दस्तावेज़ अपडेट करें +**सप्ताह 4:** एकीकरण परीक्षण और बग फिक्स + +## भविष्य के विचार + +अन्य डेटाबेस कॉन्फ़िगरेशन (जैसे, Elasticsearch) के लिए इस पैटर्न को विस्तारित करने पर विचार करें +कॉन्फ़िगरेशन सत्यापन और बेहतर त्रुटि संदेश लागू करें +कैसेंड्रा कनेक्शन पूलिंग कॉन्फ़िगरेशन के लिए समर्थन जोड़ें +कॉन्फ़िगरेशन फ़ाइल समर्थन (.env फ़ाइलें) जोड़ने पर विचार करें \ No newline at end of file diff --git a/docs/tech-specs/cassandra-consolidation.pt.md b/docs/tech-specs/cassandra-consolidation.pt.md new file mode 100644 index 00000000..b07fc919 --- /dev/null +++ b/docs/tech-specs/cassandra-consolidation.pt.md @@ -0,0 +1,331 @@ +# Especificação Técnica: Consolidação da Configuração do Cassandra + +**Status:** Rascunho +**Autor:** Assistente +**Data:** 2024-09-03 + +## Visão Geral + +Esta especificação aborda os padrões de nomenclatura e configuração inconsistentes para os parâmetros de conexão do Cassandra em todo o código-fonte do TrustGraph. Atualmente, existem dois esquemas de nomenclatura de parâmetros diferentes (`cassandra_*` vs `graph_*`), o que leva à confusão e à complexidade da manutenção. + +## Declaração do Problema + +O código-fonte atualmente usa dois conjuntos distintos de parâmetros de configuração do Cassandra: + +1. **Módulos Knowledge/Config/Library** usam: + `cassandra_host` (lista de hosts) + `cassandra_user` + `cassandra_password` + +2. **Módulos Graph/Storage** usam: + `graph_host` (um único host, às vezes convertido em lista) + `graph_username` + `graph_password` + +3. **Exposição inconsistente na linha de comando**: + Alguns processadores (por exemplo, `kg-store`) não expõem as configurações do Cassandra como argumentos de linha de comando + Outros processadores os expõem com nomes e formatos diferentes + O texto de ajuda não reflete os valores padrão das variáveis de ambiente + +Ambos os conjuntos de parâmetros se conectam ao mesmo cluster Cassandra, mas com convenções de nomenclatura diferentes, causando: +Confusão na configuração para os usuários +Aumento da carga de manutenção +Documentação inconsistente +Potencial para configuração incorreta +Impossibilidade de substituir as configurações via linha de comando em alguns processadores + +## Solução Proposta + +### 1. Padronização dos Nomes dos Parâmetros + +Todos os módulos usarão nomes de parâmetros `cassandra_*` consistentes: +`cassandra_host` - Lista de hosts (armazenada internamente como lista) +`cassandra_username` - Nome de usuário para autenticação +`cassandra_password` - Senha para autenticação + +### 2. Argumentos da Linha de Comando + +Todos os processadores DEVEM expor a configuração do Cassandra por meio de argumentos de linha de comando: +`--cassandra-host` - Lista separada por vírgulas de hosts +`--cassandra-username` - Nome de usuário para autenticação +`--cassandra-password` - Senha para autenticação + +### 3. Fallback de Variáveis de Ambiente + +Se os parâmetros da linha de comando não forem fornecidos explicitamente, o sistema verificará as variáveis de ambiente: +`CASSANDRA_HOST` - Lista separada por vírgulas de hosts +`CASSANDRA_USERNAME` - Nome de usuário para autenticação +`CASSANDRA_PASSWORD` - Senha para autenticação + +### 4. Valores Padrão + +Se nem os parâmetros da linha de comando nem as variáveis de ambiente forem especificados: +`cassandra_host` tem como padrão `["cassandra"]` +`cassandra_username` tem como padrão `None` (sem autenticação) +`cassandra_password` tem como padrão `None` (sem autenticação) + +### 5. Requisitos do Texto de Ajuda + +A saída `--help` deve: +Mostrar os valores das variáveis de ambiente como padrões quando definidos +Nunca exibir valores de senha (exibir `****` ou `` em vez disso) +Indicar claramente a ordem de resolução no texto de ajuda + +Exemplo de saída de ajuda: +``` +--cassandra-host HOST + Cassandra host list, comma-separated (default: prod-cluster-1,prod-cluster-2) + [from CASSANDRA_HOST environment variable] + +--cassandra-username USERNAME + Cassandra username (default: cassandra_user) + [from CASSANDRA_USERNAME environment variable] + +--cassandra-password PASSWORD + Cassandra password (default: ) +``` + +## Detalhes de Implementação + +### Ordem de Resolução de Parâmetros + +Para cada parâmetro do Cassandra, a ordem de resolução será: +1. Valor do argumento de linha de comando +2. Variável de ambiente (`CASSANDRA_*`) +3. Valor padrão + +### Tratamento de Parâmetros de Host + +O parâmetro `cassandra_host`: +A linha de comando aceita uma string separada por vírgulas: `--cassandra-host "host1,host2,host3"` +A variável de ambiente aceita uma string separada por vírgulas: `CASSANDRA_HOST="host1,host2,host3"` +Internamente sempre armazenado como uma lista: `["host1", "host2", "host3"]` +Host único: `"localhost"` → convertido para `["localhost"]` +Já é uma lista: `["host1", "host2"]` → usado como está + +### Lógica de Autenticação + +A autenticação será usada quando tanto `cassandra_username` quanto `cassandra_password` forem fornecidos: +```python +if cassandra_username and cassandra_password: + # Use SSL context and PlainTextAuthProvider +else: + # Connect without authentication +``` + +## Arquivos a serem modificados + +### Módulos que utilizam parâmetros `graph_*` (a serem alterados): +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/rows/cassandra/write.py` +`trustgraph-flow/trustgraph/query/triples/cassandra/service.py` + +### Módulos que utilizam parâmetros `cassandra_*` (a serem atualizados com fallback do ambiente): +`trustgraph-flow/trustgraph/tables/config.py` +`trustgraph-flow/trustgraph/tables/knowledge.py` +`trustgraph-flow/trustgraph/tables/library.py` +`trustgraph-flow/trustgraph/storage/knowledge/store.py` +`trustgraph-flow/trustgraph/cores/knowledge.py` +`trustgraph-flow/trustgraph/librarian/librarian.py` +`trustgraph-flow/trustgraph/librarian/service.py` +`trustgraph-flow/trustgraph/config/service/service.py` +`trustgraph-flow/trustgraph/cores/service.py` + +### Arquivos de teste a serem atualizados: +`tests/unit/test_cores/test_knowledge_manager.py` +`tests/unit/test_storage/test_triples_cassandra_storage.py` +`tests/unit/test_query/test_triples_cassandra_query.py` +`tests/integration/test_objects_cassandra_integration.py` + +## Estratégia de implementação + +### Fase 1: Criar um utilitário de configuração comum +Crie funções utilitárias para padronizar a configuração do Cassandra em todos os processadores: + +```python +import os +import argparse + +def get_cassandra_defaults(): + """Get default values from environment variables or fallback.""" + return { + 'host': os.getenv('CASSANDRA_HOST', 'cassandra'), + 'username': os.getenv('CASSANDRA_USERNAME'), + 'password': os.getenv('CASSANDRA_PASSWORD') + } + +def add_cassandra_args(parser: argparse.ArgumentParser): + """ + Add standardized Cassandra arguments to an argument parser. + Shows environment variable values in help text. + """ + defaults = get_cassandra_defaults() + + # Format help text with env var indication + host_help = f"Cassandra host list, comma-separated (default: {defaults['host']})" + if 'CASSANDRA_HOST' in os.environ: + host_help += " [from CASSANDRA_HOST]" + + username_help = f"Cassandra username" + if defaults['username']: + username_help += f" (default: {defaults['username']})" + if 'CASSANDRA_USERNAME' in os.environ: + username_help += " [from CASSANDRA_USERNAME]" + + password_help = "Cassandra password" + if defaults['password']: + password_help += " (default: )" + if 'CASSANDRA_PASSWORD' in os.environ: + password_help += " [from CASSANDRA_PASSWORD]" + + parser.add_argument( + '--cassandra-host', + default=defaults['host'], + help=host_help + ) + + parser.add_argument( + '--cassandra-username', + default=defaults['username'], + help=username_help + ) + + parser.add_argument( + '--cassandra-password', + default=defaults['password'], + help=password_help + ) + +def resolve_cassandra_config(args) -> tuple[list[str], str|None, str|None]: + """ + Convert argparse args to Cassandra configuration. + + Returns: + tuple: (hosts_list, username, password) + """ + # Convert host string to list + if isinstance(args.cassandra_host, str): + hosts = [h.strip() for h in args.cassandra_host.split(',')] + else: + hosts = args.cassandra_host + + return hosts, args.cassandra_username, args.cassandra_password +``` + +### Fase 2: Atualizar Módulos Usando Parâmetros `graph_*` +1. Alterar os nomes dos parâmetros de `graph_*` para `cassandra_*` +2. Substituir os métodos personalizados `add_args()` por métodos padronizados `add_cassandra_args()` +3. Usar as funções auxiliares de configuração comuns +4. Atualizar as strings de documentação + +Exemplo de transformação: +```python +# OLD CODE +@staticmethod +def add_args(parser): + parser.add_argument( + '-g', '--graph-host', + default="localhost", + help=f'Graph host (default: localhost)' + ) + parser.add_argument( + '--graph-username', + default=None, + help=f'Cassandra username' + ) + +# NEW CODE +@staticmethod +def add_args(parser): + FlowProcessor.add_args(parser) + add_cassandra_args(parser) # Use standard helper +``` + +### Fase 3: Atualizar Módulos Usando Parâmetros `cassandra_*` +1. Adicionar suporte para argumentos de linha de comando onde estiver faltando (por exemplo, `kg-store`) +2. Substituir as definições de argumentos existentes por `add_cassandra_args()` +3. Usar `resolve_cassandra_config()` para resolução consistente +4. Garantir o tratamento consistente da lista de hosts + +### Fase 4: Atualizar Testes e Documentação +1. Atualizar todos os arquivos de teste para usar os novos nomes de parâmetros +2. Atualizar a documentação da CLI +3. Atualizar a documentação da API +4. Adicionar documentação de variáveis de ambiente + +## Compatibilidade com Versões Anteriores + +Para manter a compatibilidade com versões anteriores durante a transição: + +1. **Avisos de descontinuação** para parâmetros `graph_*` +2. **Aliasing de parâmetros** - aceitar tanto os nomes antigos quanto os novos inicialmente +3. **Implementação gradual** ao longo de várias versões +4. **Atualizações na documentação** com um guia de migração + +Exemplo de código de compatibilidade com versões anteriores: +```python +def __init__(self, **params): + # Handle deprecated graph_* parameters + if 'graph_host' in params: + warnings.warn("graph_host is deprecated, use cassandra_host", DeprecationWarning) + params.setdefault('cassandra_host', params.pop('graph_host')) + + if 'graph_username' in params: + warnings.warn("graph_username is deprecated, use cassandra_username", DeprecationWarning) + params.setdefault('cassandra_username', params.pop('graph_username')) + + # ... continue with standard resolution +``` + +## Estratégia de Testes + +1. **Testes unitários** para a lógica de resolução de configuração +2. **Testes de integração** com várias combinações de configuração +3. **Testes de variáveis de ambiente** +4. **Testes de compatibilidade retroativa** com parâmetros obsoletos +5. **Testes do Docker Compose** com variáveis de ambiente + +## Atualizações da Documentação + +1. Atualizar toda a documentação dos comandos da linha de comando +2. Atualizar a documentação da API +3. Criar um guia de migração +4. Atualizar os exemplos do Docker Compose +5. Atualizar a documentação de referência de configuração + +## Riscos e Mitigações + +| Risco | Impacto | Mitigação | +|------|--------|------------| +| Mudanças que podem afetar os usuários | Alto | Implementar um período de compatibilidade retroativa | +| Confusão na configuração durante a transição | Médio | Documentação clara e avisos de descontinuação | +| Falhas nos testes | Médio | Atualizações abrangentes nos testes | +| Problemas de implantação do Docker | Alto | Atualizar todos os exemplos do Docker Compose | + +## Critérios de Sucesso + +[ ] Todos os módulos usam nomes de parâmetros `cassandra_*` consistentes +[ ] Todos os processadores expõem as configurações do Cassandra por meio de argumentos da linha de comando +[ ] O texto de ajuda da linha de comando mostra os valores padrão das variáveis de ambiente +[ ] Os valores de senha nunca são exibidos no texto de ajuda +[ ] O fallback de variáveis de ambiente funciona corretamente +[ ] `cassandra_host` é tratado de forma consistente como uma lista internamente +[ ] A compatibilidade retroativa é mantida por pelo menos 2 versões +[ ] Todos os testes passam com o novo sistema de configuração +[ ] A documentação está totalmente atualizada +[ ] Os exemplos do Docker Compose funcionam com variáveis de ambiente + +## Cronograma + +**Semana 1:** Implementar o utilitário de configuração comum e atualizar os módulos `graph_*` +**Semana 2:** Adicionar suporte a variáveis de ambiente aos módulos `cassandra_*` existentes +**Semana 3:** Atualizar testes e documentação +**Semana 4:** Testes de integração e correção de bugs + +## Considerações Futuras + +Considerar a extensão desse padrão para outras configurações de banco de dados (por exemplo, Elasticsearch) +Implementar validação de configuração e melhores mensagens de erro +Adicionar suporte para configuração de pool de conexões do Cassandra +Considerar a adição de suporte para arquivos de configuração (.env) \ No newline at end of file diff --git a/docs/tech-specs/cassandra-consolidation.ru.md b/docs/tech-specs/cassandra-consolidation.ru.md new file mode 100644 index 00000000..3b9ddee4 --- /dev/null +++ b/docs/tech-specs/cassandra-consolidation.ru.md @@ -0,0 +1,331 @@ +# Техническое описание: Консолидация конфигурации Cassandra + +**Статус:** Черновик +**Автор:** Assistant +**Дата:** 2024-09-03 + +## Обзор + +Данное техническое описание посвящено неконсистентности именования и шаблонов конфигурации параметров подключения к Cassandra в кодовой базе TrustGraph. В настоящее время существуют две различные схемы именования параметров (`cassandra_*` против `graph_*`), что приводит к путанице и усложняет обслуживание. + +## Описание проблемы + +В кодовой базе в настоящее время используются два различных набора параметров конфигурации Cassandra: + +1. **Модули Knowledge/Config/Library** используют: + `cassandra_host` (список хостов) + `cassandra_user` + `cassandra_password` + +2. **Модули Graph/Storage** используют: + `graph_host` (один хост, иногда преобразуется в список) + `graph_username` + `graph_password` + +3. **Неконсистентное использование в командной строке**: + Некоторые процессоры (например, `kg-store`) не предоставляют параметры Cassandra в качестве аргументов командной строки + Другие процессоры предоставляют их с разными именами и форматами + Тексты справки не отражают значения переменных окружения по умолчанию + +Оба набора параметров подключаются к одному кластеру Cassandra, но с разными соглашениями об именовании, что приводит к: +Путанице в конфигурации для пользователей +Увеличенной нагрузке на обслуживание +Неконсистентной документации +Возможности неправильной конфигурации +Невозможности перезаписать настройки через командную строку в некоторых процессорах + +## Предлагаемое решение + +### 1. Стандартизация имен параметров + +Все модули будут использовать согласованные имена параметров `cassandra_*`: +`cassandra_host` - Список хостов (хранится внутри как список) +`cassandra_username` - Имя пользователя для аутентификации +`cassandra_password` - Пароль для аутентификации + +### 2. Аргументы командной строки + +Все процессоры ДОЛЖНЫ предоставлять конфигурацию Cassandra через аргументы командной строки: +`--cassandra-host` - Список хостов, разделенный запятыми +`--cassandra-username` - Имя пользователя для аутентификации +`--cassandra-password` - Пароль для аутентификации + +### 3. Передача через переменные окружения + +Если параметры командной строки не указаны явно, система будет проверять переменные окружения: +`CASSANDRA_HOST` - Список хостов, разделенный запятыми +`CASSANDRA_USERNAME` - Имя пользователя для аутентификации +`CASSANDRA_PASSWORD` - Пароль для аутентификации + +### 4. Значения по умолчанию + +Если ни параметры командной строки, ни переменные окружения не указаны: +`cassandra_host` по умолчанию `["cassandra"]` +`cassandra_username` по умолчанию `None` (без аутентификации) +`cassandra_password` по умолчанию `None` (без аутентификации) + +### 5. Требования к тексту справки + +Вывод команды `--help` должен: +Показывать значения переменных окружения в качестве значений по умолчанию, если они установлены +Никогда не отображать значения паролей (показывать `****` или `` вместо этого) +Четко указывать порядок разрешения в тексте справки + +Пример вывода справки: +``` +--cassandra-host HOST + Cassandra host list, comma-separated (default: prod-cluster-1,prod-cluster-2) + [from CASSANDRA_HOST environment variable] + +--cassandra-username USERNAME + Cassandra username (default: cassandra_user) + [from CASSANDRA_USERNAME environment variable] + +--cassandra-password PASSWORD + Cassandra password (default: ) +``` + +## Детали реализации + +### Порядок разрешения параметров + +Для каждого параметра Cassandra порядок разрешения будет следующим: +1. Значение аргумента командной строки +2. Значение переменной окружения (`CASSANDRA_*`) +3. Значение по умолчанию + +### Обработка параметров хостов + +Параметр `cassandra_host`: +Командная строка принимает строку, разделенную запятыми: `--cassandra-host "host1,host2,host3"` +Переменная окружения принимает строку, разделенную запятыми: `CASSANDRA_HOST="host1,host2,host3"` +Внутри всегда хранится в виде списка: `["host1", "host2", "host3"]` +Один хост: `"localhost"` → преобразуется в `["localhost"]` +Уже является списком: `["host1", "host2"]` → используется как есть + +### Логика аутентификации + +Аутентификация будет использоваться, когда указаны и `cassandra_username`, и `cassandra_password`: +```python +if cassandra_username and cassandra_password: + # Use SSL context and PlainTextAuthProvider +else: + # Connect without authentication +``` + +## Файлы для изменения + +### Модули, использующие параметры `graph_*` (которые необходимо изменить): +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/rows/cassandra/write.py` +`trustgraph-flow/trustgraph/query/triples/cassandra/service.py` + +### Модули, использующие параметры `cassandra_*` (которые необходимо обновить с использованием резервного варианта из среды): +`trustgraph-flow/trustgraph/tables/config.py` +`trustgraph-flow/trustgraph/tables/knowledge.py` +`trustgraph-flow/trustgraph/tables/library.py` +`trustgraph-flow/trustgraph/storage/knowledge/store.py` +`trustgraph-flow/trustgraph/cores/knowledge.py` +`trustgraph-flow/trustgraph/librarian/librarian.py` +`trustgraph-flow/trustgraph/librarian/service.py` +`trustgraph-flow/trustgraph/config/service/service.py` +`trustgraph-flow/trustgraph/cores/service.py` + +### Тестовые файлы для обновления: +`tests/unit/test_cores/test_knowledge_manager.py` +`tests/unit/test_storage/test_triples_cassandra_storage.py` +`tests/unit/test_query/test_triples_cassandra_query.py` +`tests/integration/test_objects_cassandra_integration.py` + +## Стратегия реализации + +### Этап 1: Создание общего вспомогательного класса конфигурации +Создайте вспомогательные функции для стандартизации конфигурации Cassandra во всех процессорах: + +```python +import os +import argparse + +def get_cassandra_defaults(): + """Get default values from environment variables or fallback.""" + return { + 'host': os.getenv('CASSANDRA_HOST', 'cassandra'), + 'username': os.getenv('CASSANDRA_USERNAME'), + 'password': os.getenv('CASSANDRA_PASSWORD') + } + +def add_cassandra_args(parser: argparse.ArgumentParser): + """ + Add standardized Cassandra arguments to an argument parser. + Shows environment variable values in help text. + """ + defaults = get_cassandra_defaults() + + # Format help text with env var indication + host_help = f"Cassandra host list, comma-separated (default: {defaults['host']})" + if 'CASSANDRA_HOST' in os.environ: + host_help += " [from CASSANDRA_HOST]" + + username_help = f"Cassandra username" + if defaults['username']: + username_help += f" (default: {defaults['username']})" + if 'CASSANDRA_USERNAME' in os.environ: + username_help += " [from CASSANDRA_USERNAME]" + + password_help = "Cassandra password" + if defaults['password']: + password_help += " (default: )" + if 'CASSANDRA_PASSWORD' in os.environ: + password_help += " [from CASSANDRA_PASSWORD]" + + parser.add_argument( + '--cassandra-host', + default=defaults['host'], + help=host_help + ) + + parser.add_argument( + '--cassandra-username', + default=defaults['username'], + help=username_help + ) + + parser.add_argument( + '--cassandra-password', + default=defaults['password'], + help=password_help + ) + +def resolve_cassandra_config(args) -> tuple[list[str], str|None, str|None]: + """ + Convert argparse args to Cassandra configuration. + + Returns: + tuple: (hosts_list, username, password) + """ + # Convert host string to list + if isinstance(args.cassandra_host, str): + hosts = [h.strip() for h in args.cassandra_host.split(',')] + else: + hosts = args.cassandra_host + + return hosts, args.cassandra_username, args.cassandra_password +``` + +### Фаза 2: Обновление модулей с использованием параметров `graph_*` +1. Изменить имена параметров с `graph_*` на `cassandra_*` +2. Заменить собственные методы `add_args()` на стандартизированные методы `add_cassandra_args()` +3. Использовать общие вспомогательные функции конфигурации +4. Обновить строки документации + +Пример преобразования: +```python +# OLD CODE +@staticmethod +def add_args(parser): + parser.add_argument( + '-g', '--graph-host', + default="localhost", + help=f'Graph host (default: localhost)' + ) + parser.add_argument( + '--graph-username', + default=None, + help=f'Cassandra username' + ) + +# NEW CODE +@staticmethod +def add_args(parser): + FlowProcessor.add_args(parser) + add_cassandra_args(parser) # Use standard helper +``` + +### Фаза 3: Обновление модулей с использованием параметров `cassandra_*` +1. Добавить поддержку аргументов командной строки там, где это отсутствует (например, `kg-store`). +2. Заменить существующие определения аргументов на `add_cassandra_args()`. +3. Использовать `resolve_cassandra_config()` для обеспечения согласованности разрешения. +4. Обеспечить согласованную обработку списка хостов. + +### Фаза 4: Обновление тестов и документации +1. Обновить все файлы тестов для использования новых имен параметров. +2. Обновить документацию CLI. +3. Обновить документацию API. +4. Добавить документацию по переменным окружения. + +## Обратная совместимость + +Для поддержания обратной совместимости во время перехода: + +1. **Предупреждения об устаревании** для параметров `graph_*`. +2. **Псевдонимы параметров** - изначально принимать как старые, так и новые имена. +3. **Поэтапное внедрение** в течение нескольких релизов. +4. **Обновления документации** с руководством по миграции. + +Пример кода обратной совместимости: +```python +def __init__(self, **params): + # Handle deprecated graph_* parameters + if 'graph_host' in params: + warnings.warn("graph_host is deprecated, use cassandra_host", DeprecationWarning) + params.setdefault('cassandra_host', params.pop('graph_host')) + + if 'graph_username' in params: + warnings.warn("graph_username is deprecated, use cassandra_username", DeprecationWarning) + params.setdefault('cassandra_username', params.pop('graph_username')) + + # ... continue with standard resolution +``` + +## Стратегия тестирования + +1. **Юнит-тесты** для логики разрешения конфигурации +2. **Интеграционные тесты** с различными комбинациями конфигурации +3. **Тесты переменных окружения** +4. **Тесты обратной совместимости** с устаревшими параметрами +5. **Тесты Docker Compose** с переменными окружения + +## Обновления документации + +1. Обновить всю документацию по командам CLI +2. Обновить документацию API +3. Создать руководство по миграции +4. Обновить примеры Docker Compose +5. Обновить справочную документацию по конфигурации + +## Риски и меры по их снижению + +| Риск | Влияние | Меры по снижению | +|------|--------|------------| +| Изменения, нарушающие работу пользователей | Высокое | Реализовать период обратной совместимости | +| Спутанность конфигурации во время перехода | Среднее | Четкая документация и предупреждения об устаревании | +| Сбои в тестах | Среднее | Комплексное обновление тестов | +| Проблемы при развертывании Docker | Высокое | Обновить все примеры Docker Compose | + +## Критерии успеха + +[ ] Все модули используют согласованные имена параметров `cassandra_*` +[ ] Все процессоры предоставляют настройки Cassandra через аргументы командной строки +[ ] Текстовая справка по командной строке показывает значения переменных окружения по умолчанию +[ ] Значения паролей никогда не отображаются в справке +[ ] Механизм отката к переменным окружения работает правильно +[ ] `cassandra_host` последовательно обрабатывается как список внутри +[ ] Обратная совместимость поддерживается не менее 2 версий +[ ] Все тесты проходят с новой системой конфигурации +[ ] Документация полностью обновлена +[ ] Примеры Docker Compose работают с переменными окружения + +## План + +**Неделя 1:** Реализовать общий помощник конфигурации и обновить модули `graph_*` +**Неделя 2:** Добавить поддержку переменных окружения в существующие модули `cassandra_*` +**Неделя 3:** Обновить тесты и документацию +**Неделя 4:** Интеграционное тестирование и исправление ошибок + +## Будущие соображения + +Рассмотреть возможность расширения этой модели на другие конфигурации баз данных (например, Elasticsearch) +Реализовать проверку конфигурации и улучшенные сообщения об ошибках +Добавить поддержку конфигурации пула соединений Cassandra +Рассмотреть возможность добавления поддержки файлов конфигурации (.env) \ No newline at end of file diff --git a/docs/tech-specs/cassandra-consolidation.sw.md b/docs/tech-specs/cassandra-consolidation.sw.md new file mode 100644 index 00000000..1a512c6c --- /dev/null +++ b/docs/tech-specs/cassandra-consolidation.sw.md @@ -0,0 +1,331 @@ +# Maelekezo ya Kisaikolojia: Uunganishaji wa Vipengele vya Usanidi wa Cassandra + +**Hali:** Rasimu +**Mwandishi:** Msaidizi +**Tarehe:** 2024-09-03 + +## Muhtasari + +Maelekezo haya yanashughulikia utofauti katika majina na mifumo ya usanidi kwa vigezo vya muunganisho wa Cassandra katika mfumo wa TrustGraph. Kwa sasa, mifumo miwili tofauti ya majina ya vigezo ipo (`cassandra_*` vs `graph_*`), ambayo husababisha mchanganyiko na ugumu wa matengenezo. + +## Tatizo + +Mfumo wa programu hutumia seti mbili tofauti za vigezo vya usanidi wa Cassandra: + +1. **Moduli za /Config/Library za Maarifa** hutumia: + `cassandra_host` (orodha ya seva) + `cassandra_user` + `cassandra_password` + +2. **Moduli za /Storage za Grafu** hutumia: + `graph_host` (seva moja, wakati mwingine hubadilishwa kuwa orodha) + `graph_username` + `graph_password` + +3. **Uonyeshaji usio sawa wa amri:** + Baadhi ya vichakata (e.g., `kg-store`) hazionyeshi mipangilio ya Cassandra kama hoja za amri + Vichakata vingine huonyesha kwa majina na muundo tofauti + Nakala ya usaidizi haionyeshi maadili chaguo-msingi ya vigezo vya mazingira + +Seti zote mbili za vigezo zinaunganisha na kundi sawa la Cassandra lakini kwa mikataba tofauti ya majina, na kusababisha: +Mchanganyiko wa usanidi kwa watumiaji +Ongezeko la mzigo wa matengenezo +Nyaraka zisizo sawa +Uwezekano wa usanidi usio sahihi +Uwezo wa kutofanya ubadilishaji wa mipangilio kupitia hoja za amri katika vichakata vingine + +## Suluhisho Lililopendekezwa + +### 1. Kuweka Majina ya Vigezo + +Moduli zote zitatumia majina sawa ya vigezo ya `cassandra_*`: +`cassandra_host` - Orodha ya seva (hifadhiwa ndani kama orodha) +`cassandra_username` - Jina la mtumiaji kwa uthibitishaji +`cassandra_password` - Nenosiri kwa uthibitishaji + +### 2. Hoja za Amri + +Vichakata vyote WILIVYO na kuonyesha usanidi wa Cassandra kupitia hoja za amri: +`--cassandra-host` - Orodha iliyoachwa na alama ya mwelekeo wa koma ya seva +`--cassandra-username` - Jina la mtumiaji kwa uthibitishaji +`--cassandra-password` - Nenosiri kwa uthibitishaji + +### 3. Usaidizi wa Vigezo vya Mazingira + +Ikiwa hoja za amri hazitolewi wazi, mfumo utangalia vigezo vya mazingira: +`CASSANDRA_HOST` - Orodha iliyoachwa na alama ya mwelekeo wa koma ya seva +`CASSANDRA_USERNAME` - Jina la mtumiaji kwa uthibitishaji +`CASSANDRA_PASSWORD` - Nenosiri kwa uthibitishaji + +### 4. Maadili Chaguo-msingi + +Ikiwa hoja za amri wala vigezo vya mazingira hazibainishwi: +`cassandra_host` huanguka kwenye `["cassandra"]` +`cassandra_username` huanguka kwenye `None` (hakuna uthibitishaji) +`cassandra_password` huanguka kwenye `None` (hakuna uthibitishaji) + +### 5. Mahitaji ya Nakala ya Usaidizi + +Pato la `--help` lazima: +Kuonyesha maadili ya vigezo vya mazingira kama chaguo-msingi wakati yamepangwa +Kamwe kuonyesha maadili ya nenosiri (onyesha `****` au `` badala yake) +Kuonyesha wazi utaratibu wa utatuzi katika nakala ya usaidizi + +Mfano wa pato la usaidizi: +``` +--cassandra-host HOST + Cassandra host list, comma-separated (default: prod-cluster-1,prod-cluster-2) + [from CASSANDRA_HOST environment variable] + +--cassandra-username USERNAME + Cassandra username (default: cassandra_user) + [from CASSANDRA_USERNAME environment variable] + +--cassandra-password PASSWORD + Cassandra password (default: ) +``` + +## Maelezo ya Utendaji + +### Utaratibu wa Uamuzi wa Vigezo + +Kwa kila kiparamu cha Cassandra, utaratibu wa uamuzi utakuwa: +1. Thamani ya hoja ya mstari wa amri +2. Kigezo cha mazingira (`CASSANDRA_*`) +3. Thamani chaguo-msingi + +### Usimamizi wa Kiparamu cha Host + +Kiparamu cha `cassandra_host`: +Mstari wa amri unapokea mnyororo ulioachiliwa na alama ya kung'aa: `--cassandra-host "host1,host2,host3"` +Kigezo cha mazingira kinapokea mnyororo ulioachiliwa na alama ya kung'aa: `CASSANDRA_HOST="host1,host2,host3"` +Daima kuhifadhiwa kama orodha ndani: `["host1", "host2", "host3"]` +Host moja: `"localhost"` → inabadilishwa kuwa `["localhost"]` +Tayari ni orodha: `["host1", "host2"]` → inatumika kama ilivyo + +### Mantiki ya Uthibitisho + +Uthibitisho utatumika wakati `cassandra_username` na `cassandra_password` zote zimetolewa: +```python +if cassandra_username and cassandra_password: + # Use SSL context and PlainTextAuthProvider +else: + # Connect without authentication +``` + +## Faili Zinazohitaji Marekebisho + +### Moduli zinazotumia vigezo vya `graph_*` (zinazohitaji kubadilishwa): +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/rows/cassandra/write.py` +`trustgraph-flow/trustgraph/query/triples/cassandra/service.py` + +### Moduli zinazotumia vigezo vya `cassandra_*` (zinazohitaji kusasishwa na chaguo-msingi la mazingira): +`trustgraph-flow/trustgraph/tables/config.py` +`trustgraph-flow/trustgraph/tables/knowledge.py` +`trustgraph-flow/trustgraph/tables/library.py` +`trustgraph-flow/trustgraph/storage/knowledge/store.py` +`trustgraph-flow/trustgraph/cores/knowledge.py` +`trustgraph-flow/trustgraph/librarian/librarian.py` +`trustgraph-flow/trustgraph/librarian/service.py` +`trustgraph-flow/trustgraph/config/service/service.py` +`trustgraph-flow/trustgraph/cores/service.py` + +### Faili za Majaribio Zinazohitaji Kusasishwa: +`tests/unit/test_cores/test_knowledge_manager.py` +`tests/unit/test_storage/test_triples_cassandra_storage.py` +`tests/unit/test_query/test_triples_cassandra_query.py` +`tests/integration/test_objects_cassandra_integration.py` + +## Mbinu ya Utendaji + +### Hatua ya 1: Unda Msaidizi wa Mpangilio wa Msingi +Unda kazi za matumizi ili kuhakikisha mpangilio wa Cassandra ni sawa katika vichakata vyote: + +```python +import os +import argparse + +def get_cassandra_defaults(): + """Get default values from environment variables or fallback.""" + return { + 'host': os.getenv('CASSANDRA_HOST', 'cassandra'), + 'username': os.getenv('CASSANDRA_USERNAME'), + 'password': os.getenv('CASSANDRA_PASSWORD') + } + +def add_cassandra_args(parser: argparse.ArgumentParser): + """ + Add standardized Cassandra arguments to an argument parser. + Shows environment variable values in help text. + """ + defaults = get_cassandra_defaults() + + # Format help text with env var indication + host_help = f"Cassandra host list, comma-separated (default: {defaults['host']})" + if 'CASSANDRA_HOST' in os.environ: + host_help += " [from CASSANDRA_HOST]" + + username_help = f"Cassandra username" + if defaults['username']: + username_help += f" (default: {defaults['username']})" + if 'CASSANDRA_USERNAME' in os.environ: + username_help += " [from CASSANDRA_USERNAME]" + + password_help = "Cassandra password" + if defaults['password']: + password_help += " (default: )" + if 'CASSANDRA_PASSWORD' in os.environ: + password_help += " [from CASSANDRA_PASSWORD]" + + parser.add_argument( + '--cassandra-host', + default=defaults['host'], + help=host_help + ) + + parser.add_argument( + '--cassandra-username', + default=defaults['username'], + help=username_help + ) + + parser.add_argument( + '--cassandra-password', + default=defaults['password'], + help=password_help + ) + +def resolve_cassandra_config(args) -> tuple[list[str], str|None, str|None]: + """ + Convert argparse args to Cassandra configuration. + + Returns: + tuple: (hosts_list, username, password) + """ + # Convert host string to list + if isinstance(args.cassandra_host, str): + hosts = [h.strip() for h in args.cassandra_host.split(',')] + else: + hosts = args.cassandra_host + + return hosts, args.cassandra_username, args.cassandra_password +``` + +### Awamu ya 2: Sasisha Moduli Ukitumia Vigezo vya `graph_*` +1. Badilisha majina ya vigezo kutoka `graph_*` hadi `cassandra_*` +2. Badilisha mbinu (methods) maalum za `add_args()` kwa mbinu za kawaida za `add_cassandra_args()` +3. Tumia kazi (functions) za kawaida za usaidizi wa usanidi +4. Sasisha maandishi ya utangazaji (documentation strings) + +Mfano wa mabadiliko: +```python +# OLD CODE +@staticmethod +def add_args(parser): + parser.add_argument( + '-g', '--graph-host', + default="localhost", + help=f'Graph host (default: localhost)' + ) + parser.add_argument( + '--graph-username', + default=None, + help=f'Cassandra username' + ) + +# NEW CODE +@staticmethod +def add_args(parser): + FlowProcessor.add_args(parser) + add_cassandra_args(parser) # Use standard helper +``` + +### Awamu ya 3: Sasisha Moduli Ukitumia Vigezo vya `cassandra_*` +1. Ongeza uunganisha wa hoja za mstari wa amri ambapo haipo (k.m., `kg-store`) +2. Badilisha ufafanuzi wa hoja zilizopo kwa `add_cassandra_args()` +3. Tumia `resolve_cassandra_config()` kwa utaratibu thabiti +4. Hakikisha utunzaji thabiti wa orodha ya seva + +### Awamu ya 4: Sasisha Vipimo na Nyaraka +1. Sasisha faili zote za vipimo ili zitumie majina mapya ya vigezo +2. Sasisha nyaraka za CLI +3. Sasisha nyaraka za API +4. Ongeza nyaraka za vigezo vya mazingira + +## Ulinganishaji na Mifumo ya Zamani + +Ili kudumisha ulinganishaji na mifumo ya zamani wakati wa mabadiliko: + +1. **Maonyo ya kutolewa nje** kwa vigezo vya `graph_*` +2. **Ujumuishaji wa vigezo** - kukubali majina ya zamani na mapya awali +3. **Utoaji wa hatua kwa hatua** katika matoleo mengi +4. **Sasisho za nyaraka** pamoja na mwongozo wa uhamishaji + +Mfano wa msimbo wa ulinganishaji na mifumo ya zamani: +```python +def __init__(self, **params): + # Handle deprecated graph_* parameters + if 'graph_host' in params: + warnings.warn("graph_host is deprecated, use cassandra_host", DeprecationWarning) + params.setdefault('cassandra_host', params.pop('graph_host')) + + if 'graph_username' in params: + warnings.warn("graph_username is deprecated, use cassandra_username", DeprecationWarning) + params.setdefault('cassandra_username', params.pop('graph_username')) + + # ... continue with standard resolution +``` + +## Mbinu ya Majaribio + +1. **Majaribio ya kitengo** kwa mantiki ya utatuzi wa usanidi +2. **Majaribio ya ujumuishaji** na mchanganyiko mbalimbali wa usanidi +3. **Majaribio ya vigezo vya mazingira** +4. **Majaribio ya utangamano wa nyuma** na vigezo vilivyotolewa +5. **Majaribio ya Docker compose** na vigezo vya mazingira + +## Sasisho za Nyaraka + +1. Sasisha nyaraka zote za amri za CLI +2. Sasisha nyaraka za API +3. Unda mwongozo wa uhamishaji +4. Sasisha mifano ya Docker compose +5. Sasisha nyaraka za kumbukumbu ya usanidi + +## Hatari na Kupunguza Madhara + +| Hatari | Athari | Kupunguza Madhara | +|------|--------|------------| +| Mabadiliko yanayoweza kusababisha matatizo kwa watumiaji | Ya juu | Tekeleza kipindi cha utangamano wa nyuma | +| Uchanganyifu wa usanidi wakati wa mabadiliko | Ya kati | Nyaraka wazi na onyo la kutolewa | +| Kushindwa kwa majaribio | Ya kati | Sasisho kamili ya majaribio | +| Matatizo ya usakinishaji wa Docker | Ya juu | Sasisha mifano yote ya Docker compose | + +## Vigezo vya Mafanikio + +[ ] Moduli zote hutumia majina ya vigezo `cassandra_*` yanayofanana +[ ] Wasindikaji wote huonyesha mipangilio ya Cassandra kupitia hoja za mstari wa amri +[ ] Nakala ya msaada wa mstari wa amri inaonyesha chaguo-msingi ya vigezo vya mazingira +[ ] Maelezo ya nenosiri hayajaonyeshwa katika nakala ya msaada +[ ] Mfumo wa kurudisha nyuma wa vigezo vya mazingira unafanya kazi vizuri +[ ] `cassandra_host` inashughulikiwa kwa utaratibu kama orodha ndani +[ ] Utangamano wa nyuma umeendelezwa kwa angalau matoleo 2 +[ ] Majaribio yote hupita na mfumo mpya wa usanidi +[ ] Nyaraka zimesasishwa kikamilifu +[ ] Mifano ya Docker compose inafanya kazi na vigezo vya mazingira + +## Ratiba + +**Wiki ya 1:** Tekeleza kusaidia usanidi wa kawaida na sasisha moduli za `graph_*` +**Wiki ya 2:** Ongeza usaidizi wa vigezo vya mazingira kwa moduli zilizopo za `cassandra_*` +**Wiki ya 3:** Sasisha majaribio na nyaraka +**Wiki ya 4:** Majaribio ya ujumuishaji na urekebishaji wa hitilafu + +## Mambo ya Kuzingatia ya Baadaye + +Fikiria kuongeza muundo huu kwa usanidi mwingine wa hifadhidata (e.g., Elasticsearch) +Tekeleza uthibitisho wa usanidi na ujumbe bora wa kosa +Ongeza usaidizi wa usanidi wa muunganisho wa Cassandra (e.g., pooli) +Fikiria kuongeza usaidizi wa faili za usanidi (.env files) \ No newline at end of file diff --git a/docs/tech-specs/cassandra-consolidation.tr.md b/docs/tech-specs/cassandra-consolidation.tr.md new file mode 100644 index 00000000..e9f15bbb --- /dev/null +++ b/docs/tech-specs/cassandra-consolidation.tr.md @@ -0,0 +1,331 @@ +# Cassandra Yapılandırma Birleştirme: Teknik Özellikler + +**Durum:** Taslak +**Yazar:** Yardımcı +**Tarih:** 2024-09-03 + +## Genel Bakış + +Bu özellik, TrustGraph kod tabanındaki Cassandra bağlantı parametreleri için tutarsız adlandırma ve yapılandırma kalıplarını ele almaktadır. Şu anda, iki farklı parametre adlandırma şeması bulunmaktadır (`cassandra_*` ve `graph_*`), bu da kafa karışıklığına ve bakım karmaşıklığına yol açmaktadır. + +## Sorun Tanımı + +Kod tabanı şu anda iki farklı Cassandra yapılandırma parametre seti kullanmaktadır: + +1. **Bilgi/Yapılandırma/Kütüphane modülleri** aşağıdaki parametreleri kullanır: + `cassandra_host` (sunucu listesi) + `cassandra_user` + `cassandra_password` + +2. **Grafik/Depolama modülleri** aşağıdaki parametreleri kullanır: + `graph_host` (tek bir sunucu, bazen listeye dönüştürülür) + `graph_username` + `graph_password` + +3. **Tutarsız komut satırı kullanımı**: + Bazı işleme birimleri (örneğin, `kg-store`), Cassandra ayarlarını komut satırı argümanları olarak sunmaz + Diğer işleme birimleri bunları farklı adlar ve formatlarla sunar + Yardım metni, ortam değişkeni varsayılanlarını yansıtmaz + +Her iki parametre seti de aynı Cassandra kümesine bağlanır, ancak farklı adlandırma kuralları kullanır, bu da şunlara neden olur: +Kullanıcılar için yapılandırma karışıklığı +Artan bakım yükü +Tutarsız dokümantasyon +Yanlış yapılandırma riski +Bazı işleme birimlerinde ayarları komut satırı aracılığıyla geçersiz kılma imkansızlığı + +## Önerilen Çözüm + +### 1. Parametre Adlarını Standartlaştırın + +Tüm modüller, tutarlı `cassandra_*` parametre adlarını kullanacaktır: +`cassandra_host` - Sunucu listesi (içeride liste olarak saklanır) +`cassandra_username` - Kimlik doğrulama için kullanıcı adı +`cassandra_password` - Kimlik doğrulama için parola + +### 2. Komut Satırı Argümanları + +TÜM işleme birimleri, Cassandra yapılandırmasını komut satırı argümanları aracılığıyla sunmalıdır: +`--cassandra-host` - Virgülle ayrılmış sunucu listesi +`--cassandra-username` - Kimlik doğrulama için kullanıcı adı +`--cassandra-password` - Kimlik doğrulama için parola + +### 3. Ortam Değişkeni Geri Düşüşü + +Komut satırı parametreleri açıkça sağlanmadığında, sistem ortam değişkenlerini kontrol edecektir: +`CASSANDRA_HOST` - Virgülle ayrılmış sunucu listesi +`CASSANDRA_USERNAME` - Kimlik doğrulama için kullanıcı adı +`CASSANDRA_PASSWORD` - Kimlik doğrulama için parola + +### 4. Varsayılan Değerler + +Ne komut satırı parametreleri ne de ortam değişkenleri belirtilmediğinde: +`cassandra_host`, `["cassandra"]`'e varsayılan olarak ayarlanır +`cassandra_username`, `None`'e (kimlik doğrulama yok) varsayılan olarak ayarlanır +`cassandra_password`, `None`'e (kimlik doğrulama yok) varsayılan olarak ayarlanır + +### 5. Yardım Metni Gereksinimleri + +`--help` çıktısı şunları içermelidir: +Ortam değişkeni değerleri ayarlandığında, bunları varsayılan değerler olarak göstermelidir +Parola değerlerini asla göstermemelidir (bunun yerine `****` veya `` göstermelidir) +Çözüm sırasını yardım metninde açıkça belirtmelidir + +Örnek yardım çıktısı: +``` +--cassandra-host HOST + Cassandra host list, comma-separated (default: prod-cluster-1,prod-cluster-2) + [from CASSANDRA_HOST environment variable] + +--cassandra-username USERNAME + Cassandra username (default: cassandra_user) + [from CASSANDRA_USERNAME environment variable] + +--cassandra-password PASSWORD + Cassandra password (default: ) +``` + +## Uygulama Detayları + +### Parametre Çözümleme Sırası + +Her Cassandra parametresi için, çözümleme sırası aşağıdaki olacaktır: +1. Komut satırı argümanı değeri +2. Ortam değişkeni (`CASSANDRA_*`) +3. Varsayılan değer + +### Ana Bilgisayar Parametreleri Yönetimi + +`cassandra_host` parametresi: +Komut satırı, virgülle ayrılmış bir dize kabul eder: `--cassandra-host "host1,host2,host3"` +Ortam değişkeni, virgülle ayrılmış bir dize kabul eder: `CASSANDRA_HOST="host1,host2,host3"` +İçeride her zaman bir liste olarak saklanır: `["host1", "host2", "host3"]` +Tek bir ana bilgisayar: `"localhost"` → `["localhost"]`'e dönüştürülür +Zaten bir liste: `["host1", "host2"]` → olduğu gibi kullanılır + +### Kimlik Doğrulama Mantığı + +Kimlik doğrulama, hem `cassandra_username` hem de `cassandra_password` sağlandığında kullanılacaktır: +```python +if cassandra_username and cassandra_password: + # Use SSL context and PlainTextAuthProvider +else: + # Connect without authentication +``` + +## Değiştirilecek Dosyalar + +### `graph_*` parametrelerini kullanan modüller (değiştirilecek): +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/rows/cassandra/write.py` +`trustgraph-flow/trustgraph/query/triples/cassandra/service.py` + +### `cassandra_*` parametrelerini kullanan modüller (ortam değişkeni geri dönüşü ile güncellenecek): +`trustgraph-flow/trustgraph/tables/config.py` +`trustgraph-flow/trustgraph/tables/knowledge.py` +`trustgraph-flow/trustgraph/tables/library.py` +`trustgraph-flow/trustgraph/storage/knowledge/store.py` +`trustgraph-flow/trustgraph/cores/knowledge.py` +`trustgraph-flow/trustgraph/librarian/librarian.py` +`trustgraph-flow/trustgraph/librarian/service.py` +`trustgraph-flow/trustgraph/config/service/service.py` +`trustgraph-flow/trustgraph/cores/service.py` + +### Güncellenecek Test Dosyaları: +`tests/unit/test_cores/test_knowledge_manager.py` +`tests/unit/test_storage/test_triples_cassandra_storage.py` +`tests/unit/test_query/test_triples_cassandra_query.py` +`tests/integration/test_objects_cassandra_integration.py` + +## Uygulama Stratejisi + +### Aşama 1: Ortak Yapılandırma Yardımcı Programı Oluşturma +Tüm işlemcilerde Cassandra yapılandırmasını standartlaştırmak için yardımcı işlevler oluşturun: + +```python +import os +import argparse + +def get_cassandra_defaults(): + """Get default values from environment variables or fallback.""" + return { + 'host': os.getenv('CASSANDRA_HOST', 'cassandra'), + 'username': os.getenv('CASSANDRA_USERNAME'), + 'password': os.getenv('CASSANDRA_PASSWORD') + } + +def add_cassandra_args(parser: argparse.ArgumentParser): + """ + Add standardized Cassandra arguments to an argument parser. + Shows environment variable values in help text. + """ + defaults = get_cassandra_defaults() + + # Format help text with env var indication + host_help = f"Cassandra host list, comma-separated (default: {defaults['host']})" + if 'CASSANDRA_HOST' in os.environ: + host_help += " [from CASSANDRA_HOST]" + + username_help = f"Cassandra username" + if defaults['username']: + username_help += f" (default: {defaults['username']})" + if 'CASSANDRA_USERNAME' in os.environ: + username_help += " [from CASSANDRA_USERNAME]" + + password_help = "Cassandra password" + if defaults['password']: + password_help += " (default: )" + if 'CASSANDRA_PASSWORD' in os.environ: + password_help += " [from CASSANDRA_PASSWORD]" + + parser.add_argument( + '--cassandra-host', + default=defaults['host'], + help=host_help + ) + + parser.add_argument( + '--cassandra-username', + default=defaults['username'], + help=username_help + ) + + parser.add_argument( + '--cassandra-password', + default=defaults['password'], + help=password_help + ) + +def resolve_cassandra_config(args) -> tuple[list[str], str|None, str|None]: + """ + Convert argparse args to Cassandra configuration. + + Returns: + tuple: (hosts_list, username, password) + """ + # Convert host string to list + if isinstance(args.cassandra_host, str): + hosts = [h.strip() for h in args.cassandra_host.split(',')] + else: + hosts = args.cassandra_host + + return hosts, args.cassandra_username, args.cassandra_password +``` + +### 2. Aşama: `graph_*` Parametrelerini Kullanan Modülleri Güncelleme +1. Parametre adlarını `graph_*`'dan `cassandra_*`'e değiştirin. +2. Özel `add_args()` yöntemlerini standart `add_cassandra_args()` yöntemleriyle değiştirin. +3. Ortak yapılandırma yardımcı fonksiyonlarını kullanın. +4. Dokümantasyon metinlerini güncelleyin. + +Örnek dönüşüm: +```python +# OLD CODE +@staticmethod +def add_args(parser): + parser.add_argument( + '-g', '--graph-host', + default="localhost", + help=f'Graph host (default: localhost)' + ) + parser.add_argument( + '--graph-username', + default=None, + help=f'Cassandra username' + ) + +# NEW CODE +@staticmethod +def add_args(parser): + FlowProcessor.add_args(parser) + add_cassandra_args(parser) # Use standard helper +``` + +### 3. Aşama: `cassandra_*` Parametrelerini Kullanarak Modülleri Güncelleme +1. Eksik olan yerlerde komut satırı argümanı desteğini ekleyin (örneğin, `kg-store`) +2. Mevcut argüman tanımlarını `add_cassandra_args()` ile değiştirin +3. Tutarlı çözümleme için `resolve_cassandra_config()`'ı kullanın +4. Tutarlı ana bilgisayar listesi işleme sağlayın + +### 4. Aşama: Testleri ve Belgeleri Güncelleme +1. Tüm test dosyalarını yeni parametre adlarını kullanacak şekilde güncelleyin +2. Komut satırı (CLI) belgelerini güncelleyin +3. API belgelerini güncelleyin +4. Ortam değişkeni belgelerini ekleyin + +## Geriye Dönük Uyumluluk + +Geçiş sırasında geriye dönük uyumluluğu korumak için: + +1. `graph_*` parametreleri için **kullanımdan kaldırma uyarıları** +2. **Parametre takma adları** - başlangıçta hem eski hem de yeni adları kabul edin +3. **Aşamalı dağıtım** birden fazla sürümde +4. **Belge güncellemeleri** ve geçiş kılavuzu + +Örnek geriye dönük uyumluluk kodu: +```python +def __init__(self, **params): + # Handle deprecated graph_* parameters + if 'graph_host' in params: + warnings.warn("graph_host is deprecated, use cassandra_host", DeprecationWarning) + params.setdefault('cassandra_host', params.pop('graph_host')) + + if 'graph_username' in params: + warnings.warn("graph_username is deprecated, use cassandra_username", DeprecationWarning) + params.setdefault('cassandra_username', params.pop('graph_username')) + + # ... continue with standard resolution +``` + +## Test Stratejisi + +1. **Birim testleri**, yapılandırma çözümleme mantığı için +2. **Entegrasyon testleri**, çeşitli yapılandırma kombinasyonlarıyla +3. **Ortam değişkeni testleri** +4. **Geriye dönük uyumluluk testleri**, kullanımdan kaldırılmış parametrelerle +5. **Docker compose testleri**, ortam değişkenleriyle + +## Dokümantasyon Güncellemeleri + +1. Tüm CLI komutu dokümantasyonunu güncelleyin +2. API dokümantasyonunu güncelleyin +3. Geçiş kılavuzu oluşturun +4. Docker compose örneklerini güncelleyin +5. Yapılandırma referans dokümantasyonunu güncelleyin + +## Riskler ve Azaltma + +| Risk | Etki | Azaltma | +|------|--------|------------| +| Kullanıcılar için bozucu değişiklikler | Yüksek | Geriye dönük uyumluluk süresi uygulayın | +| Geçiş sırasında yapılandırma karışıklığı | Orta | Açık dokümantasyon ve kullanımdan kaldırma uyarıları | +| Test hataları | Orta | Kapsamlı test güncellemeleri | +| Docker dağıtım sorunları | Yüksek | Tüm Docker compose örneklerini güncelleyin | + +## Başarı Kriterleri + +[ ] Tüm modüller, tutarlı `cassandra_*` parametre adlarını kullanır +[ ] Tüm işlemciler, Cassandra ayarlarını komut satırı argümanları aracılığıyla sunar +[ ] Komut satırı yardım metni, ortam değişkeni varsayılanlarını gösterir +[ ] Parola değerleri, yardım metninde asla görüntülenmez +[ ] Ortam değişkeni yedeklemesi doğru şekilde çalışır +[ ] `cassandra_host`, dahili olarak tutarlı bir şekilde bir liste olarak işlenir +[ ] Geriye dönüştürülebilirlik, en az 2 sürüm için korunur +[ ] Tüm testler, yeni yapılandırma sistemiyle geçer +[ ] Dokümantasyon tamamen güncellenmiştir +[ ] Docker compose örnekleri, ortam değişkenleriyle çalışır + +## Zaman Çizelgesi + +**1. Hafta:** Ortak yapılandırma yardımcı programını uygulayın ve `graph_*` modüllerini güncelleyin +**2. Hafta:** Mevcut `cassandra_*` modüllerine ortam değişkeni desteği ekleyin +**3. Hafta:** Testleri ve dokümantasyonu güncelleyin +**4. Hafta:** Entegrasyon testi ve hata düzeltmeleri + +## Gelecek Hususlar + +Bu kalıbı diğer veritabanı yapılandırmalarına (örneğin, Elasticsearch) genişletmeyi düşünün +Yapılandırma doğrulama ve daha iyi hata mesajları uygulayın +Cassandra bağlantı havuzu yapılandırması desteği ekleyin +Yapılandırma dosyası desteği eklemeyi düşünün (.env dosyaları) \ No newline at end of file diff --git a/docs/tech-specs/cassandra-consolidation.zh-cn.md b/docs/tech-specs/cassandra-consolidation.zh-cn.md new file mode 100644 index 00000000..18f1698d --- /dev/null +++ b/docs/tech-specs/cassandra-consolidation.zh-cn.md @@ -0,0 +1,331 @@ +# 技术规范:Cassandra 配置整合 + +**状态:** 草稿 +**作者:** 助理 +**日期:** 2024-09-03 + +## 概述 + +本规范旨在解决 TrustGraph 代码库中 Cassandra 连接参数命名和配置模式的不一致问题。目前,存在两种不同的参数命名方案(`cassandra_*` 与 `graph_*`),这导致了混乱和维护复杂性。 + +## 问题陈述 + +当前代码库使用两组不同的 Cassandra 配置参数: + +1. **知识/配置/库模块** 使用: + `cassandra_host` (主机列表) + `cassandra_user` + `cassandra_password` + +2. **图/存储模块** 使用: + `graph_host` (单个主机,有时转换为列表) + `graph_username` + `graph_password` + +3. **命令行暴露不一致:** + 一些处理器(例如,`kg-store`)不将 Cassandra 设置作为命令行参数暴露 + 其他处理器以不同的名称和格式暴露这些设置 + 帮助文本未反映环境变量的默认值 + +这两组参数都连接到同一个 Cassandra 集群,但使用不同的命名约定,导致: +用户配置混乱 +维护负担增加 +文档不一致 +可能出现配置错误 +在某些处理器中,无法通过命令行覆盖设置 + +## 解决方案 + +### 1. 标准化参数名称 + +所有模块都将使用一致的 `cassandra_*` 参数名称: +`cassandra_host` - 主机列表(内部存储为列表) +`cassandra_username` - 身份验证用户名 +`cassandra_password` - 身份验证密码 + +### 2. 命令行参数 + +所有处理器都必须通过命令行参数暴露 Cassandra 配置: +`--cassandra-host` - 逗号分隔的主机列表 +`--cassandra-username` - 身份验证用户名 +`--cassandra-password` - 身份验证密码 + +### 3. 环境变量回退 + +如果未显式提供命令行参数,系统将检查环境变量: +`CASSANDRA_HOST` - 逗号分隔的主机列表 +`CASSANDRA_USERNAME` - 身份验证用户名 +`CASSANDRA_PASSWORD` - 身份验证密码 + +### 4. 默认值 + +如果未指定命令行参数或环境变量: +`cassandra_host` 默认为 `["cassandra"]` +`cassandra_username` 默认为 `None` (无身份验证) +`cassandra_password` 默认为 `None` (无身份验证) + +### 5. 帮助文本要求 + +`--help` 输出必须: +显示已设置的环境变量值作为默认值 +绝不显示密码值(显示 `****` 或 `` 代替) +在帮助文本中清楚地指示解析顺序 + +示例帮助输出: +``` +--cassandra-host HOST + Cassandra host list, comma-separated (default: prod-cluster-1,prod-cluster-2) + [from CASSANDRA_HOST environment variable] + +--cassandra-username USERNAME + Cassandra username (default: cassandra_user) + [from CASSANDRA_USERNAME environment variable] + +--cassandra-password PASSWORD + Cassandra password (default: ) +``` + +## 实现细节 + +### 参数解析顺序 + +对于每个 Cassandra 参数,解析顺序如下: +1. 命令行参数值 +2. 环境变量 (`CASSANDRA_*`) +3. 默认值 + +### 主机参数处理 + +`cassandra_host` 参数: +命令行接受逗号分隔的字符串:`--cassandra-host "host1,host2,host3"` +环境变量接受逗号分隔的字符串:`CASSANDRA_HOST="host1,host2,host3"` +内部始终存储为列表:`["host1", "host2", "host3"]` +单个主机:`"localhost"` → 转换为 `["localhost"]` +已经是列表:`["host1", "host2"]` → 保持原样 + +### 认证逻辑 + +当同时提供 `cassandra_username` 和 `cassandra_password` 时,将使用认证: +```python +if cassandra_username and cassandra_password: + # Use SSL context and PlainTextAuthProvider +else: + # Connect without authentication +``` + +## 需要修改的文件 + +### 使用 `graph_*` 参数的模块(需要修改): +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/rows/cassandra/write.py` +`trustgraph-flow/trustgraph/query/triples/cassandra/service.py` + +### 使用 `cassandra_*` 参数的模块(需要更新,并使用环境变量回退): +`trustgraph-flow/trustgraph/tables/config.py` +`trustgraph-flow/trustgraph/tables/knowledge.py` +`trustgraph-flow/trustgraph/tables/library.py` +`trustgraph-flow/trustgraph/storage/knowledge/store.py` +`trustgraph-flow/trustgraph/cores/knowledge.py` +`trustgraph-flow/trustgraph/librarian/librarian.py` +`trustgraph-flow/trustgraph/librarian/service.py` +`trustgraph-flow/trustgraph/config/service/service.py` +`trustgraph-flow/trustgraph/cores/service.py` + +### 需要更新的测试文件: +`tests/unit/test_cores/test_knowledge_manager.py` +`tests/unit/test_storage/test_triples_cassandra_storage.py` +`tests/unit/test_query/test_triples_cassandra_query.py` +`tests/integration/test_objects_cassandra_integration.py` + +## 实施策略 + +### 第一阶段:创建通用的配置辅助工具 +创建实用函数,以标准化所有处理器中的 Cassandra 配置: + +```python +import os +import argparse + +def get_cassandra_defaults(): + """Get default values from environment variables or fallback.""" + return { + 'host': os.getenv('CASSANDRA_HOST', 'cassandra'), + 'username': os.getenv('CASSANDRA_USERNAME'), + 'password': os.getenv('CASSANDRA_PASSWORD') + } + +def add_cassandra_args(parser: argparse.ArgumentParser): + """ + Add standardized Cassandra arguments to an argument parser. + Shows environment variable values in help text. + """ + defaults = get_cassandra_defaults() + + # Format help text with env var indication + host_help = f"Cassandra host list, comma-separated (default: {defaults['host']})" + if 'CASSANDRA_HOST' in os.environ: + host_help += " [from CASSANDRA_HOST]" + + username_help = f"Cassandra username" + if defaults['username']: + username_help += f" (default: {defaults['username']})" + if 'CASSANDRA_USERNAME' in os.environ: + username_help += " [from CASSANDRA_USERNAME]" + + password_help = "Cassandra password" + if defaults['password']: + password_help += " (default: )" + if 'CASSANDRA_PASSWORD' in os.environ: + password_help += " [from CASSANDRA_PASSWORD]" + + parser.add_argument( + '--cassandra-host', + default=defaults['host'], + help=host_help + ) + + parser.add_argument( + '--cassandra-username', + default=defaults['username'], + help=username_help + ) + + parser.add_argument( + '--cassandra-password', + default=defaults['password'], + help=password_help + ) + +def resolve_cassandra_config(args) -> tuple[list[str], str|None, str|None]: + """ + Convert argparse args to Cassandra configuration. + + Returns: + tuple: (hosts_list, username, password) + """ + # Convert host string to list + if isinstance(args.cassandra_host, str): + hosts = [h.strip() for h in args.cassandra_host.split(',')] + else: + hosts = args.cassandra_host + + return hosts, args.cassandra_username, args.cassandra_password +``` + +### 第二阶段:使用 `graph_*` 参数更新模块 +1. 将参数名称从 `graph_*` 更改为 `cassandra_*` +2. 将自定义 `add_args()` 方法替换为标准化的 `add_cassandra_args()` +3. 使用通用的配置辅助函数 +4. 更新文档字符串 + +示例转换: +```python +# OLD CODE +@staticmethod +def add_args(parser): + parser.add_argument( + '-g', '--graph-host', + default="localhost", + help=f'Graph host (default: localhost)' + ) + parser.add_argument( + '--graph-username', + default=None, + help=f'Cassandra username' + ) + +# NEW CODE +@staticmethod +def add_args(parser): + FlowProcessor.add_args(parser) + add_cassandra_args(parser) # Use standard helper +``` + +### 第三阶段:使用 `cassandra_*` 参数更新模块 +1. 在缺失的地方添加命令行参数支持(例如:`kg-store`) +2. 将现有的参数定义替换为 `add_cassandra_args()` +3. 使用 `resolve_cassandra_config()` 以实现一致的解析 +4. 确保一致的主机列表处理 + +### 第四阶段:更新测试和文档 +1. 更新所有测试文件以使用新的参数名称 +2. 更新命令行界面 (CLI) 文档 +3. 更新 API 文档 +4. 添加环境变量文档 + +## 向后兼容性 + +为了在过渡期间保持向后兼容性: + +1. **弃用警告**,用于 `graph_*` 参数 +2. **参数别名** - 初始阶段接受旧名称和新名称 +3. **分阶段发布**,在多个版本中进行 +4. **文档更新**,包含迁移指南 + +示例向后兼容代码: +```python +def __init__(self, **params): + # Handle deprecated graph_* parameters + if 'graph_host' in params: + warnings.warn("graph_host is deprecated, use cassandra_host", DeprecationWarning) + params.setdefault('cassandra_host', params.pop('graph_host')) + + if 'graph_username' in params: + warnings.warn("graph_username is deprecated, use cassandra_username", DeprecationWarning) + params.setdefault('cassandra_username', params.pop('graph_username')) + + # ... continue with standard resolution +``` + +## 测试策略 + +1. **单元测试**,用于配置解析逻辑 +2. **集成测试**,使用各种配置组合 +3. **环境变量测试** +4. **向后兼容性测试**,针对已弃用的参数 +5. **Docker Compose 测试**,使用环境变量 + +## 文档更新 + +1. 更新所有 CLI 命令文档 +2. 更新 API 文档 +3. 创建迁移指南 +4. 更新 Docker Compose 示例 +5. 更新配置参考文档 + +## 风险与缓解 + +| 风险 | 影响 | 缓解措施 | +|------|--------|------------| +| 对用户的破坏性更改 | 高 | 实施向后兼容性过渡期 | +| 转换期间的配置混淆 | 中 | 清晰的文档和弃用警告 | +| 测试失败 | 中 | 全面的测试更新 | +| Docker 部署问题 | 高 | 更新所有 Docker Compose 示例 | + +## 成功标准 + +[ ] 所有模块使用一致的 `cassandra_*` 参数名称 +[ ] 所有处理器通过命令行参数暴露 Cassandra 设置 +[ ] 命令行帮助文本显示环境变量的默认值 +[ ] 密码值绝不在帮助文本中显示 +[ ] 环境变量回退工作正常 +[ ] `cassandra_host` 内部始终被处理为列表 +[ ] 至少在 2 个版本中保持向后兼容性 +[ ] 所有测试在新配置系统中通过 +[ ] 文档已完全更新 +[ ] Docker Compose 示例使用环境变量 + +## 时间线 + +**第一周:** 实施通用的配置助手,并更新 `graph_*` 模块 +**第二周:** 为现有的 `cassandra_*` 模块添加环境变量支持 +**第三周:** 更新测试和文档 +**第四周:** 集成测试和错误修复 + +## 未来考虑 + +考虑将此模式扩展到其他数据库配置(例如,Elasticsearch) +实施配置验证和更好的错误消息 +添加对 Cassandra 连接池配置的支持 +考虑添加对配置文件支持(.env 文件) \ No newline at end of file diff --git a/docs/tech-specs/cassandra-performance-refactor.ar.md b/docs/tech-specs/cassandra-performance-refactor.ar.md new file mode 100644 index 00000000..51761613 --- /dev/null +++ b/docs/tech-specs/cassandra-performance-refactor.ar.md @@ -0,0 +1,679 @@ +# المواصفات الفنية: إعادة هيكلة أداء قاعدة المعرفة Cassandra + +**الحالة:** مسودة +**المؤلف:** مساعد +**التاريخ:** 2025-09-18 + +## نظرة عامة + +تتناول هذه المواصفة مشكلات الأداء في تطبيق قاعدة المعرفة Cassandra TrustGraph وتقترح تحسينات لتخزين واستعلام ثلاثيات RDF. + +## التنفيذ الحالي + +### تصميم المخطط + +يستخدم التنفيذ الحالي تصميم جدول واحد في `trustgraph-flow/trustgraph/direct/cassandra_kg.py`: + +```sql +CREATE TABLE triples ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` + +**الفهارس الثانوية:** +`triples_s` على `s` (الموضوع) +`triples_p` على `p` (المُتَعَدِّي) +`triples_o` على `o` (المفعول به) + +### أنماط الاستعلام + +تدعم التنفيذ الحالي 8 أنماط استعلام متميزة: + +1. **get_all(collection, limit=50)** - استرجاع جميع الثلاثيات لمجموعة + ```sql + SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50 + ``` + +2. **get_s(collection, s, limit=10)** - الاستعلام بناءً على الموضوع. + ```sql + SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10 + ``` + +3. **get_p(collection, p, limit=10)** - الاستعلام بناءً على شرط. + ```sql + SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10 + ``` + +4. **get_o(collection, o, limit=10)** - الاستعلام بناءً على الكائن. + ```sql + SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10 + ``` + +5. **get_sp(collection, s, p, limit=10)** - الاستعلام بناءً على الموضوع + المسند. + ```sql + SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10 + ``` + +6. **get_po(collection, p, o, limit=10)** - الاستعلام بناءً على الشرط + الكائن ⚠️ + ```sql + SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING + ``` + +7. **get_os(collection, o, s, limit=10)** - الاستعلام بناءً على الكائن والموضوع ⚠️ + ```sql + SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING + ``` + +8. **get_spo(collection, s, p, o, limit=10)** - تطابق ثلاثي دقيق. + ```sql + SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10 + ``` + +### البنية التحتية الحالية + +**الملف: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`** +فئة `KnowledgeGraph` واحدة تتعامل مع جميع العمليات. +تجميع الاتصالات من خلال قائمة `_active_clusters` عامة. +اسم جدول ثابت: `"triples"`. +مساحة مفاتيح لكل نموذج مستخدم. +استنساخ SimpleStrategy بعامل 1. + +**نقاط التكامل:** +**مسار الكتابة:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`. +**مسار الاستعلام:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py`. +**مخزن المعرفة:** `trustgraph-flow/trustgraph/tables/knowledge.py`. + +## المشكلات المتعلقة بالأداء التي تم تحديدها + +### مشكلات على مستوى المخطط + +1. **تصميم مفتاح أساسي غير فعال** + الحالي: `PRIMARY KEY (collection, s, p, o)`. + يؤدي إلى تجميع ضعيف لأنماط الوصول الشائعة. + يجبر على استخدام فهرس ثانوي مكلف. + +2. **إفراط في استخدام الفهرس الثانوي** ⚠️ + ثلاثة فهارس ثانوية على أعمدة ذات قيم عالية (s، p، o). + الفهارس الثانوية في Cassandra مكلفة ولا تتوسع بشكل جيد. + تتطلب الاستعلامات 6 و 7 `ALLOW FILTERING` مما يشير إلى نموذج بيانات ضعيف. + +3. **خطر التقسيم الساخن** + يمكن أن يؤدي مفتاح التقسيم الواحد `collection` إلى إنشاء تقسيمات ساخنة. + ستتركز المجموعات الكبيرة على عقد فردية. + لا توجد استراتيجية توزيع لتحقيق موازنة التحميل. + +### مشكلات على مستوى الاستعلام + +1. **استخدام ALLOW FILTERING** ⚠️ + يتطلب نوعان من الاستعلامات (get_po، get_os) `ALLOW FILTERING`. + هذه الاستعلامات تفحص العديد من التقسيمات وهي مكلفة للغاية. + يتدهور الأداء خطيًا مع حجم البيانات. + +2. **أنماط وصول غير فعالة** + لا توجد تحسينات لأنماط استعلام RDF الشائعة. + فهارس مركبة مفقودة لتوليفات الاستعلامات المتكررة. + لا توجد اعتبارات لأنماط اجتياز الرسم البياني. + +3. **نقص في تحسين الاستعلام** + لا يوجد تخزين مؤقت لبيانات الاستعلامات المُعدة. + لا توجد تلميحات أو استراتيجيات لتحسين الاستعلام. + لا توجد اعتبارات للتقسيم إلى صفحات تتجاوز LIMIT البسيطة. + +## بيان المشكلة + +يحتوي تطبيق قاعدة المعرفة الحالي في Cassandra على نقطتي اختناق أداء حاسمتين: + +### 1. أداء استعلام get_po غير فعال + +الاستعلام `get_po(collection, p, o)` غير فعال للغاية لأنه يتطلب `ALLOW FILTERING`: + +```sql +SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING +``` + +**لماذا هذه مشكلة:** +`ALLOW FILTERING` تجبر Cassandra على فحص جميع الأقسام داخل المجموعة. +تتدهور الأداء بشكل خطي مع حجم البيانات. +هذا نمط استعلام RDF شائع (إيجاد الموضوعات التي لها علاقة محددة بين الفاعل والمفعول به). +يؤدي ذلك إلى زيادة كبيرة في الحمل على المجموعة مع نمو البيانات. + +### 2. استراتيجية تجميع غير فعالة + +المفتاح الأساسي الحالي `PRIMARY KEY (collection, s, p, o)` يوفر فوائد تجميع محدودة: + +**المشاكل المتعلقة بالتجميع الحالي:** +`collection` كمفتاح قسم لا يوزع البيانات بشكل فعال. +تحتوي معظم المجموعات على بيانات متنوعة مما يجعل التجميع غير فعال. +لا توجد اعتبارات لأنماط الوصول الشائعة في استعلامات RDF. +تخلق المجموعات الكبيرة أقسامًا "ساخنة" على عقد فردية. +لا تعمل أعمدة التجميع (s، p، o) على تحسين أنماط اجتياز الرسم البياني النموذجية. + +**التأثير:** +لا تستفيد الاستعلامات من قرب البيانات. +استخدام ضعيف لذاكرة التخزين المؤقت. +توزيع غير متساوٍ للحمل عبر عقد المجموعة. +اختناقات في قابلية التوسع مع نمو المجموعات. + +## الحل المقترح: استراتيجية إلغاء التسوية باستخدام 4 جداول + +### نظرة عامة + +استبدل الجدول `triples` الواحد بأربعة جداول مصممة خصيصًا، كل منها مُحسَّن لأنماط استعلام محددة. هذا يلغي الحاجة إلى الفهارس الثانوية و ALLOW FILTERING مع توفير أداء مثالي لجميع أنواع الاستعلامات. يتيح الجدول الرابع حذف المجموعات بكفاءة على الرغم من مفاتيح الأقسام المركبة. + +### تصميم المخطط الجديد + +**الجدول 1: الاستعلامات المرتكزة على الموضوع (triples_s)** +```sql +CREATE TABLE triples_s ( + collection text, + s text, + p text, + o text, + PRIMARY KEY ((collection, s), p, o) +); +``` +**تحسينات:** get_s، get_sp، get_os +**مفتاح التقسيم:** (collection, s) - توزيع أفضل من مجرد استخدام collection وحده. +**التجميع:** (p, o) - يتيح عمليات بحث فعالة عن المحددات/الكائنات لكيان معين. + +**الجدول 2: استعلامات المحدد-الكائن (triples_p)** +```sql +CREATE TABLE triples_p ( + collection text, + p text, + o text, + s text, + PRIMARY KEY ((collection, p), o, s) +); +``` +**تحسين:** get_p, get_po (يزيل الحاجة إلى ALLOW FILTERING!) +**مفتاح التقسيم:** (collection, p) - وصول مباشر عبر الشرط. +**التجميع:** (o, s) - تصفح فعال للكائنات والموضوعات. + +**الجدول 3: الاستعلامات المرتكزة على الكائنات (triples_o)** +```sql +CREATE TABLE triples_o ( + collection text, + o text, + s text, + p text, + PRIMARY KEY ((collection, o), s, p) +); +``` +**التحسينات:** get_o +**مفتاح التقسيم:** (collection, o) - وصول مباشر عن طريق الكائن +**التجميع:** (s, p) - تصفح فعال للموضوع والمسند + +**الجدول 4: إدارة المجموعات والاستعلامات SPO (triples_collection)** +```sql +CREATE TABLE triples_collection ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` +**التحسينات:** get_spo، delete_collection +**مفتاح التقسيم:** مجموعة فقط - يتيح عمليات فعالة على مستوى المجموعة. +**التجميع:** (s, p, o) - ترتيب ثلاثي قياسي. +**الغرض:** استخدام مزدوج للبحث الدقيق عن SPO وكمؤشر للحذف. + +### تعيين الاستعلام + +| الاستعلام الأصلي | الجدول الهدف | تحسين الأداء | +|----------------|-------------|------------------------| +| get_all(collection) | triples_s | السماح بالتصفية (مقبول للمسح) | +| get_s(collection, s) | triples_s | وصول مباشر إلى التقسيم | +| get_p(collection, p) | triples_p | وصول مباشر إلى التقسيم | +| get_o(collection, o) | triples_o | وصول مباشر إلى التقسيم | +| get_sp(collection, s, p) | triples_s | التقسيم + التجميع | +| get_po(collection, p, o) | triples_p | **لا مزيد من السماح بالتصفية!** | +| get_os(collection, o, s) | triples_o | التقسيم + التجميع | +| get_spo(collection, s, p, o) | triples_collection | بحث مباشر عن المفتاح | +| delete_collection(collection) | triples_collection | قراءة الفهرس، حذف مجمع | + +### استراتيجية حذف المجموعة + +مع مفاتيح التقسيم المركبة، لا يمكننا ببساطة تنفيذ `DELETE FROM table WHERE collection = ?`. بدلاً من ذلك: + +1. **مرحلة القراءة:** استعلام `triples_collection` لسرد جميع الثلاثيات: + ```sql + SELECT s, p, o FROM triples_collection WHERE collection = ? + ``` + هذا فعال لأنه `collection` هو مفتاح التقسيم لهذه الجدولة. + +2. **مرحلة الحذف:** لكل ثلاثية (s, p, o)، قم بالحذف من جميع الجداول الأربعة باستخدام مفاتيح التقسيم الكاملة: + ```sql + DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ? + DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ? + DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ? + DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ? + ``` + يتم تجميع البيانات في مجموعات مكونة من 100 عنصر لتحقيق الكفاءة. + +**تحليل المقايضات:** +✅ يحافظ على الأداء الأمثل للاستعلامات مع الأقسام الموزعة. +✅ لا توجد أقسام "ساخنة" للمجموعات الكبيرة. +❌ منطق حذف أكثر تعقيدًا (قراءة ثم حذف). +❌ وقت الحذف يتناسب مع حجم المجموعة. + +### المزايا + +1. **يزيل الحاجة إلى ALLOW FILTERING** - كل استعلام لديه مسار وصول أمثل (باستثناء فحص get_all). +2. **لا توجد فهارس ثانوية** - كل جدول هو الفهرس لنمط الاستعلام الخاص به. +3. **توزيع أفضل للبيانات** - مفاتيح التقسيم المركبة توزع الحمل بشكل فعال. +4. **أداء متوقع** - وقت الاستعلام يتناسب مع حجم النتيجة، وليس إجمالي البيانات. +5. **يستفيد من نقاط قوة Cassandra** - مصمم ليتناسب مع بنية Cassandra. +6. **يمكن حذف المجموعات** - تعمل triples_collection كفهرس للحذف. + +## خطة التنفيذ + +### الملفات التي تتطلب تغييرات + +#### الملف الأساسي للتنفيذ + +**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - مطلوب إعادة كتابة كاملة. + +**الطرق الحالية التي تتطلب إعادة هيكلة:** +```python +# Schema initialization +def init(self) -> None # Replace single table with three tables + +# Insert operations +def insert(self, collection, s, p, o) -> None # Write to all three tables + +# Query operations (API unchanged, implementation optimized) +def get_all(self, collection, limit=50) # Use triples_by_subject +def get_s(self, collection, s, limit=10) # Use triples_by_subject +def get_p(self, collection, p, limit=10) # Use triples_by_po +def get_o(self, collection, o, limit=10) # Use triples_by_object +def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject +def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!) +def get_os(self, collection, o, s, limit=10) # Use triples_by_subject +def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject + +# Collection management +def delete_collection(self, collection) -> None # Delete from all three tables +``` + +#### ملفات التكامل (لا يلزم إجراء أي تغييرات منطقية) + +**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`** +لا يلزم إجراء أي تغييرات - تستخدم واجهة برمجة تطبيقات KnowledgeGraph الحالية. +تستفيد تلقائيًا من تحسينات الأداء. + +**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`** +لا يلزم إجراء أي تغييرات - تستخدم واجهة برمجة تطبيقات KnowledgeGraph الحالية. +تستفيد تلقائيًا من تحسينات الأداء. + +### ملفات الاختبار التي تتطلب تحديثات + +#### اختبارات الوحدة +**`tests/unit/test_storage/test_triples_cassandra_storage.py`** +تحديث توقعات الاختبار للتغييرات في المخطط. +إضافة اختبارات لضمان الاتساق بين الجداول المتعددة. +التحقق من عدم وجود ALLOW FILTERING في خطط الاستعلام. + +**`tests/unit/test_query/test_triples_cassandra_query.py`** +تحديث التأكيدات المتعلقة بالأداء. +اختبار جميع أنماط الاستعلام الثمانية مقابل الجداول الجديدة. +التحقق من توجيه الاستعلام إلى الجداول الصحيحة. + +#### اختبارات التكامل +**`tests/integration/test_cassandra_integration.py`** +اختبار شامل مع المخطط الجديد. +مقارنات قياس الأداء. +التحقق من اتساق البيانات عبر الجداول. + +**`tests/unit/test_storage/test_cassandra_config_integration.py`** +تحديث اختبارات التحقق من صحة المخطط. +اختبار سيناريوهات الترحيل. + +### استراتيجية التنفيذ + +#### المرحلة الأولى: المخطط والطرق الأساسية +1. **إعادة كتابة الطريقة `init()`** - إنشاء أربعة جداول بدلاً من جدول واحد. +2. **إعادة كتابة الطريقة `insert()`** - عمليات كتابة مجمعة إلى جميع الجداول الأربعة. +3. **تنفيذ عبارات مُعدة** - للحصول على أداء مثالي. +4. **إضافة منطق توجيه الجدول** - لتوجيه الاستعلامات إلى الجداول المثلى. +5. **تنفيذ حذف المجموعة** - القراءة من triples_collection، وحذف مجمع من جميع الجداول. + +#### المرحلة الثانية: تحسين طريقة الاستعلام +1. **إعادة كتابة كل طريقة get_*** لاستخدام الجدول الأمثل. +2. **إزالة جميع استخدامات ALLOW FILTERING**. +3. **تنفيذ استخدام فعال لمفتاح التجميع**. +4. **إضافة تسجيل أداء الاستعلام**. + +#### المرحلة الثالثة: إدارة المجموعة +1. **تحديث `delete_collection()`** - إزالتها من جميع الجداول الثلاثة. +2. **إضافة التحقق من الاتساق** - لضمان بقاء جميع الجداول متزامنة. +3. **تنفيذ عمليات مجمعة** - لعمليات متعددة الجداول ذرية. + +### تفاصيل التنفيذ الرئيسية + +#### استراتيجية الكتابة المجمعة +```python +def insert(self, collection, s, p, o): + batch = BatchStatement() + + # Insert into all four tables + batch.add(self.insert_subject_stmt, (collection, s, p, o)) + batch.add(self.insert_po_stmt, (collection, p, o, s)) + batch.add(self.insert_object_stmt, (collection, o, s, p)) + batch.add(self.insert_collection_stmt, (collection, s, p, o)) + + self.session.execute(batch) +``` + +#### منطق توجيه الاستعلامات +```python +def get_po(self, collection, p, o, limit=10): + # Route to triples_p table - NO ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) + +def get_spo(self, collection, s, p, o, limit=10): + # Route to triples_collection table for exact SPO lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) +``` + +#### منطق حذف المجموعة +```python +def delete_collection(self, collection): + # Step 1: Read all triples from collection table + rows = self.session.execute( + f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s", + (collection,) + ) + + # Step 2: Batch delete from all 4 tables + batch = BatchStatement() + count = 0 + + for row in rows: + s, p, o = row.s, row.p, row.o + + # Delete using full partition keys for each table + batch.add(SimpleStatement( + f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?" + ), (collection, p, o, s)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?" + ), (collection, o, s, p)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + count += 1 + + # Execute every 100 triples to avoid oversized batches + if count % 100 == 0: + self.session.execute(batch) + batch = BatchStatement() + + # Execute remaining deletions + if count % 100 != 0: + self.session.execute(batch) + + logger.info(f"Deleted {count} triples from collection {collection}") +``` + +### تحسين عبارات SQL المُعدة (Prepared Statements) +```python +def prepare_statements(self): + # Cache prepared statements for better performance + self.insert_subject_stmt = self.session.prepare( + f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + self.insert_po_stmt = self.session.prepare( + f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)" + ) + self.insert_object_stmt = self.session.prepare( + f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)" + ) + self.insert_collection_stmt = self.session.prepare( + f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + # ... query statements +``` + +## استراتيجية الترحيل + +### نهج ترحيل البيانات + +#### الخيار الأول: النشر الأزرق-الأخضر (موصى به) +1. **نشر المخطط الجديد جنبًا إلى جنب مع المخطط الحالي** - استخدم أسماء جداول مختلفة مؤقتًا. +2. **فترة الكتابة المزدوجة** - الكتابة إلى كل من المخططين القديم والجديد خلال فترة الانتقال. +3. **ترحيل البيانات في الخلفية** - نسخ البيانات الموجودة إلى الجداول الجديدة. +4. **توجيه عمليات القراءة** - توجيه الاستعلامات إلى الجداول الجديدة بمجرد ترحيل البيانات. +5. **إزالة الجداول القديمة** - بعد فترة التحقق. + +#### الخيار الثاني: الترحيل في المكان +1. **إضافة المخطط** - إنشاء جداول جديدة في مساحة المفاتيح الحالية. +2. **برنامج ترحيل البيانات** - نسخ دفعي من الجدول القديم إلى الجداول الجديدة. +3. **تحديث التطبيق** - نشر التعليمات البرمجية الجديدة بعد اكتمال الترحيل. +4. **تنظيف الجدول القديم** - إزالة الجدول القديم والفهارس. + +### التوافق مع الإصدارات السابقة + +#### استراتيجية النشر +```python +# Environment variable to control table usage during migration +USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' + +class KnowledgeGraph: + def __init__(self, ...): + if USE_LEGACY_TABLES: + self.init_legacy_schema() + else: + self.init_optimized_schema() +``` + +#### نص ترحيل +```python +def migrate_data(): + # Read from old table + old_triples = session.execute("SELECT collection, s, p, o FROM triples") + + # Batch write to new tables + for batch in batched(old_triples, 100): + batch_stmt = BatchStatement() + for row in batch: + # Add to all three new tables + batch_stmt.add(insert_subject_stmt, row) + batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s)) + batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p)) + session.execute(batch_stmt) +``` + +### استراتيجية التحقق من الصحة + +#### فحوصات تناسق البيانات +```python +def validate_migration(): + # Count total records in old vs new tables + old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,)) + new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,)) + + assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}" + + # Spot check random samples + sample_queries = generate_test_queries() + for query in sample_queries: + old_result = execute_legacy_query(query) + new_result = execute_optimized_query(query) + assert old_result == new_result, f"Query results differ for {query}" +``` + +## استراتيجية الاختبار + +### اختبار الأداء + +#### سيناريوهات قياس الأداء +1. **مقارنة أداء الاستعلامات** + مقاييس الأداء قبل وبعد لجميع أنواع الاستعلامات الثمانية. + التركيز على تحسين أداء `get_po` (إزالة `ALLOW FILTERING`). + قياس زمن استجابة الاستعلامات تحت أحجام بيانات مختلفة. + +2. **اختبار التحميل** + تنفيذ استعلامات متزامنة. + معدل نقل البيانات مع العمليات الدفعية. + استخدام الذاكرة ووحدة المعالجة المركزية. + +3. **اختبار قابلية التوسع** + الأداء مع زيادة أحجام المجموعات. + توزيع الاستعلامات عبر مجموعات متعددة. + استخدام عقد المجموعة. + +#### مجموعات بيانات الاختبار +**صغيرة:** 10 آلاف ثلاثية لكل مجموعة. +**متوسطة:** 100 ألف ثلاثية لكل مجموعة. +**كبيرة:** أكثر من مليون ثلاثية لكل مجموعة. +**مجموعات متعددة:** اختبار توزيع التقسيم. + +### اختبار وظيفي + +#### تحديثات اختبار الوحدات +```python +# Example test structure for new implementation +class TestCassandraKGPerformance: + def test_get_po_no_allow_filtering(self): + # Verify get_po queries don't use ALLOW FILTERING + with patch('cassandra.cluster.Session.execute') as mock_execute: + kg.get_po('test_collection', 'predicate', 'object') + executed_query = mock_execute.call_args[0][0] + assert 'ALLOW FILTERING' not in executed_query + + def test_multi_table_consistency(self): + # Verify all tables stay in sync + kg.insert('test', 's1', 'p1', 'o1') + + # Check all tables contain the triple + assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1') + assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1') + assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1') +``` + +#### تحديثات اختبار التكامل +```python +class TestCassandraIntegration: + def test_query_performance_regression(self): + # Ensure new implementation is faster than old + old_time = benchmark_legacy_get_po() + new_time = benchmark_optimized_get_po() + assert new_time < old_time * 0.5 # At least 50% improvement + + def test_end_to_end_workflow(self): + # Test complete write -> query -> delete cycle + # Verify no performance degradation in integration +``` + +### خطة التراجع + +#### استراتيجية تراجع سريعة +1. **تبديل متغيرات البيئة** - العودة إلى الجداول القديمة على الفور. +2. **الاحتفاظ بالجداول القديمة** - لا تقم بإزالتها حتى يتم إثبات الأداء. +3. **تنبيهات المراقبة** - تشغيل تلقائي للتراجع بناءً على معدلات الخطأ/زمن الاستجابة. + +#### التحقق من التراجع +```python +def rollback_to_legacy(): + # Set environment variable + os.environ['CASSANDRA_USE_LEGACY'] = 'true' + + # Restart services to pick up change + restart_cassandra_services() + + # Validate functionality + run_smoke_tests() +``` + +## المخاطر والاعتبارات + +### مخاطر الأداء +**زيادة زمن الاستجابة للكتابة** - 4 عمليات كتابة لكل عملية إدخال (أكثر بنسبة 33٪ من مقاربة الجدول الثلاثي) +**العبء التخزيني** - 4 أضعاف متطلبات التخزين (أكثر بنسبة 33٪ من مقاربة الجدول الثلاثي) +**فشل عمليات الكتابة المجمعة** - الحاجة إلى معالجة الأخطاء بشكل صحيح +**تعقيد الحذف** - يتطلب حذف المجموعة حلقة قراءة ثم حذف + +### المخاطر التشغيلية +**تعقيد الترحيل** - ترحيل البيانات لمجموعات البيانات الكبيرة +**تحديات الاتساق** - ضمان بقاء جميع الجداول متزامنة +**فجوات المراقبة** - الحاجة إلى مقاييس جديدة لعمليات الجداول المتعددة + +### استراتيجيات التخفيف +1. **النشر التدريجي** - ابدأ بمجموعات صغيرة +2. **مراقبة شاملة** - تتبع جميع مقاييس الأداء +3. **التحقق الآلي** - فحص الاتساق المستمر +4. **إمكانية التراجع السريع** - اختيار الجدول بناءً على البيئة + +## معايير النجاح + +### تحسينات الأداء +[ ] **إزالة ALLOW FILTERING** - تعمل الاستعلامات get_po و get_os بدون تصفية +[ ] **تقليل زمن استجابة الاستعلام** - تحسن بنسبة 50٪ أو أكثر في أوقات استجابة الاستعلام +[ ] **توزيع أفضل للعبء** - لا توجد أقسام "ساخنة"، وتوزيع متساوٍ عبر عقد المجموعة +[ ] **أداء قابل للتوسع** - وقت الاستعلام يتناسب مع حجم النتيجة، وليس إجمالي البيانات + +### المتطلبات الوظيفية +[ ] **توافق واجهة برمجة التطبيقات (API)** - يستمر جميع التعليمات البرمجية الحالية في العمل دون تغيير +[ ] **اتساق البيانات** - تظل جميع الجداول الثلاثة متزامنة +[ ] **عدم فقدان البيانات** - يحافظ الترحيل على جميع الثلاثيات الموجودة +[ ] **التوافق مع الإصدارات السابقة** - القدرة على العودة إلى المخطط القديم + +### المتطلبات التشغيلية +[ ] **ترحيل آمن** - نشر أخضر/أزرق مع إمكانية التراجع +[ ] **تغطية المراقبة** - مقاييس شاملة لعمليات الجداول المتعددة +[ ] **تغطية الاختبار** - تم اختبار جميع أنماط الاستعلام باستخدام معايير الأداء +[ ] **التوثيق** - تحديث إجراءات النشر والتشغيل + +## الجدول الزمني + +### المرحلة 1: التنفيذ +[ ] إعادة كتابة `cassandra_kg.py` باستخدام مخطط الجداول المتعددة +[ ] تنفيذ عمليات الكتابة المجمعة +[ ] إضافة تحسينات باستخدام عبارات مُعدة +[ ] تحديث اختبارات الوحدة + +### المرحلة 2: اختبار التكامل +[ ] تحديث اختبارات التكامل +[ ] قياس الأداء +[ ] اختبار التحميل باستخدام أحجام بيانات واقعية +[ ] نصوص التحقق من اتساق البيانات + +### المرحلة 3: تخطيط الترحيل +[ ] نصوص النشر الأخضر/الأزرق +[ ] أدوات ترحيل البيانات +[ ] تحديثات لوحة معلومات المراقبة +[ ] إجراءات التراجع + +### المرحلة 4: النشر في بيئة الإنتاج +[ ] النشر التدريجي في بيئة الإنتاج +[ ] مراقبة الأداء والتحقق من صحته +[ ] تنظيف الجداول القديمة +[ ] تحديثات التوثيق + +## الخلاصة + +تعالج هذه الاستراتيجية لإلغاء التسوية متعددة الجداول بشكل مباشر عنقودين رئيسيين للأداء: + +1. **تقضي على ALLOW FILTERING المكلفة** من خلال توفير هياكل جداول مثالية لكل نمط استعلام +2. **تحسين فعالية التجميع** من خلال مفاتيح التقسيم المركبة التي توزع الحمل بشكل صحيح + +تستفيد هذه الطريقة من نقاط قوة Cassandra مع الحفاظ على توافق كامل مع واجهة برمجة التطبيقات (API)، مما يضمن أن التعليمات البرمجية الحالية تستفيد تلقائيًا من تحسينات الأداء. diff --git a/docs/tech-specs/cassandra-performance-refactor.es.md b/docs/tech-specs/cassandra-performance-refactor.es.md new file mode 100644 index 00000000..f5f6c97a --- /dev/null +++ b/docs/tech-specs/cassandra-performance-refactor.es.md @@ -0,0 +1,679 @@ +# Especificación Técnica: Refactorización del Rendimiento de la Base de Conocimiento Cassandra + +**Estado:** Borrador +**Autor:** Asistente +**Fecha:** 2025-09-18 + +## Resumen + +Esta especificación aborda los problemas de rendimiento en la implementación de la base de conocimiento TrustGraph Cassandra y propone optimizaciones para el almacenamiento y la consulta de triples RDF. + +## Implementación Actual + +### Diseño del Esquema + +La implementación actual utiliza un diseño de tabla única en `trustgraph-flow/trustgraph/direct/cassandra_kg.py`: + +```sql +CREATE TABLE triples ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` + +**Índices Secundarios:** +`triples_s` EN `s` (sujeto) +`triples_p` EN `p` (predicado) +`triples_o` EN `o` (objeto) + +### Patrones de Consulta + +La implementación actual admite 8 patrones de consulta distintos: + +1. **get_all(colección, límite=50)** - Recupera todas las triples para una colección + ```sql + SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50 + ``` + +2. **get_s(colección, s, límite=10)** - Consulta por tema. + ```sql + SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10 + ``` + +3. **get_p(colección, p, límite=10)** - Consulta por predicado + ```sql + SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10 + ``` + +4. **get_o(colección, o, límite=10)** - Consulta por objeto + ```sql + SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10 + ``` + +5. **get_sp(colección, s, p, limit=10)** - Consulta por sujeto + predicado + ```sql + SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10 + ``` + +6. **get_po(collection, p, o, limit=10)** - Consulta por predicado + objeto ⚠️ + ```sql + SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING + ``` + +7. **get_os(collection, o, s, limit=10)** - Consulta por objeto + sujeto ⚠️ + ```sql + SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING + ``` + +8. **get_spo(colección, s, p, o, límite=10)** - Coincidencia exacta de tripleta. + ```sql + SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10 + ``` + +### Arquitectura Actual + +**Archivo: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`** +Clase única `KnowledgeGraph` que gestiona todas las operaciones +Agrupación de conexiones a través de una lista global `_active_clusters` +Nombre de tabla fijo: `"triples"` +Espacio de claves por modelo de usuario +Replicación SimpleStrategy con factor 1 + +**Puntos de Integración:** +**Ruta de Escritura:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +**Ruta de Consulta:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` +**Almacén de Conocimiento:** `trustgraph-flow/trustgraph/tables/knowledge.py` + +## Problemas de Rendimiento Identificados + +### Problemas a Nivel de Esquema + +1. **Diseño de Clave Primaria Ineficiente** + Actual: `PRIMARY KEY (collection, s, p, o)` + Resulta en un agrupamiento deficiente para patrones de acceso comunes + Obliga al uso de índices secundarios costosos + +2. **Uso Excesivo de Índices Secundarios** ⚠️ + Tres índices secundarios en columnas de alta cardinalidad (s, p, o) + Los índices secundarios en Cassandra son costosos y no escalan bien + Las consultas 6 y 7 requieren `ALLOW FILTERING`, lo que indica un modelado de datos deficiente + +3. **Riesgo de Particiones Calientes** + Una única clave de partición `collection` puede crear particiones calientes + Las colecciones grandes se concentrarán en nodos individuales + No hay estrategia de distribución para el equilibrio de carga + +### Problemas a Nivel de Consulta + +1. **Uso de ALLOW FILTERING** ⚠️ + Dos tipos de consulta (get_po, get_os) requieren `ALLOW FILTERING` + Estas consultas escanean múltiples particiones y son extremadamente costosas + El rendimiento disminuye linealmente con el tamaño de los datos + +2. **Patrones de Acceso Ineficientes** + No hay optimización para patrones de consulta RDF comunes + Faltan índices compuestos para combinaciones de consulta frecuentes + No se tiene en cuenta los patrones de recorrido de grafos + +3. **Falta de Optimización de Consultas** + No hay almacenamiento en caché de sentencias preparadas + No hay sugerencias de consulta ni estrategias de optimización + No se tiene en cuenta la paginación más allá de un simple LIMIT + +## Declaración del Problema + +La implementación actual de la base de conocimiento de Cassandra tiene dos cuellos de botella críticos de rendimiento: + +### 1. Rendimiento Ineficiente de la Consulta get_po + +La consulta `get_po(collection, p, o)` es extremadamente ineficiente debido a que requiere `ALLOW FILTERING`: + +```sql +SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING +``` + +**¿Por qué esto es problemático:** +`ALLOW FILTERING` obliga a Cassandra a escanear todas las particiones dentro de la colección. +El rendimiento disminuye linealmente con el tamaño de los datos. +Este es un patrón de consulta RDF común (encontrar sujetos que tengan una relación específica de predicado-objeto). +Crea una carga significativa en el clúster a medida que los datos crecen. + +### 2. Estrategia de Clustering Deficiente + +La clave primaria actual `PRIMARY KEY (collection, s, p, o)` proporciona beneficios de clustering mínimos: + +**Problemas con el clustering actual:** +`collection` como clave de partición no distribuye los datos de manera efectiva. +La mayoría de las colecciones contienen datos diversos, lo que hace que el clustering sea ineficaz. +No se tiene en cuenta los patrones de acceso comunes en las consultas RDF. +Las colecciones grandes crean particiones "calientes" en nodos individuales. +Las columnas de clustering (s, p, o) no optimizan para los patrones típicos de recorrido de grafos. + +**Impacto:** +Las consultas no se benefician de la localidad de los datos. +Utilización deficiente de la caché. +Distribución desigual de la carga en los nodos del clúster. +Cuellos de botella de escalabilidad a medida que las colecciones crecen. + +## Solución Propuesta: Estrategia de Desnormalización de 4 Tablas + +### Resumen + +Reemplace la única tabla `triples` con cuatro tablas diseñadas específicamente, cada una optimizada para patrones de consulta específicos. Esto elimina la necesidad de índices secundarios y ALLOW FILTERING, al tiempo que proporciona un rendimiento óptimo para todos los tipos de consulta. La cuarta tabla permite una eliminación eficiente de colecciones a pesar de las claves de partición compuestas. + +### Nuevo Diseño de Esquema + +**Tabla 1: Consultas Centradas en el Sujeto (triples_s)** +```sql +CREATE TABLE triples_s ( + collection text, + s text, + p text, + o text, + PRIMARY KEY ((collection, s), p, o) +); +``` +**Optimiza:** get_s, get_sp, get_os +**Clave de partición:** (colección, s) - Mejor distribución que solo la colección. +**Agrupamiento:** (p, o) - Permite búsquedas eficientes de predicados/objetos para un sujeto. + +**Tabla 2: Consultas Predicado-Objeto (triples_p)** +```sql +CREATE TABLE triples_p ( + collection text, + p text, + o text, + s text, + PRIMARY KEY ((collection, p), o, s) +); +``` +**Optimiza:** get_p, get_po (¡elimina ALLOW FILTERING!) +**Clave de partición:** (colección, p) - Acceso directo mediante predicado +**Agrupamiento:** (o, s) - Recorrido eficiente de objeto a sujeto + +**Tabla 3: Consultas centradas en objetos (triples_o)** +```sql +CREATE TABLE triples_o ( + collection text, + o text, + s text, + p text, + PRIMARY KEY ((collection, o), s, p) +); +``` +**Optimiza:** get_o +**Clave de partición:** (colección, o) - Acceso directo por objeto +**Clustering:** (s, p) - Recorrido eficiente de sujeto-predicado + +**Tabla 4: Gestión de colecciones y consultas SPO (triples_collection)** +```sql +CREATE TABLE triples_collection ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` +**Optimiza:** get_spo, delete_collection +**Clave de partición:** solo colección - Permite operaciones eficientes a nivel de colección. +**Clustering:** (s, p, o) - Orden estándar de tripletas. +**Propósito:** Uso dual para búsquedas exactas de SPO y como índice de eliminación. + +### Mapeo de consultas + +| Consulta original | Tabla de destino | Mejora de rendimiento | +|----------------|-------------|------------------------| +| get_all(collection) | triples_s | PERMITE FILTRADO (aceptable para escaneo) | +| get_s(collection, s) | triples_s | Acceso directo a la partición | +| get_p(collection, p) | triples_p | Acceso directo a la partición | +| get_o(collection, o) | triples_o | Acceso directo a la partición | +| get_sp(collection, s, p) | triples_s | Partición + clustering | +| get_po(collection, p, o) | triples_p | **¡Ya no se permite ALLOW FILTERING!** | +| get_os(collection, o, s) | triples_o | Partición + clustering | +| get_spo(collection, s, p, o) | triples_collection | Búsqueda exacta de clave | +| delete_collection(collection) | triples_collection | Lee el índice, eliminación por lotes de todos | + +### Estrategia de eliminación de colecciones + +Con claves de partición compuestas, no podemos simplemente ejecutar `DELETE FROM table WHERE collection = ?`. En cambio: + +1. **Fase de lectura:** Consulta `triples_collection` para enumerar todas las tripletas: + ```sql + SELECT s, p, o FROM triples_collection WHERE collection = ? + ``` + Esto es eficiente ya que `collection` es la clave de partición para esta tabla. + +2. **Fase de eliminación:** Para cada triple (s, p, o), elimine de las 4 tablas utilizando claves de partición completas: + ```sql + DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ? + DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ? + DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ? + DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ? + ``` + Agrupado en lotes de 100 para mayor eficiencia. + +**Análisis de compensaciones:** +✅ Mantiene un rendimiento óptimo de las consultas con particiones distribuidas. +✅ No hay particiones con alta carga para colecciones grandes. +❌ Lógica de eliminación más compleja (leer y luego eliminar). +❌ Tiempo de eliminación proporcional al tamaño de la colección. + +### Beneficios + +1. **Elimina ALLOW FILTERING** - Cada consulta tiene una ruta de acceso óptima (excepto el escaneo get_all). +2. **No se requieren índices secundarios** - Cada tabla ES el índice para su patrón de consulta. +3. **Mejor distribución de datos** - Las claves de partición compuestas distribuyen la carga de manera efectiva. +4. **Rendimiento predecible** - El tiempo de consulta es proporcional al tamaño del resultado, no a los datos totales. +5. **Aprovecha las fortalezas de Cassandra** - Diseñado para la arquitectura de Cassandra. +6. **Permite la eliminación de colecciones** - triples_collection sirve como índice de eliminación. + +## Plan de implementación + +### Archivos que requieren cambios + +#### Archivo de implementación principal + +**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - Se requiere una reescritura completa. + +**Métodos actuales a refactorizar:** +```python +# Schema initialization +def init(self) -> None # Replace single table with three tables + +# Insert operations +def insert(self, collection, s, p, o) -> None # Write to all three tables + +# Query operations (API unchanged, implementation optimized) +def get_all(self, collection, limit=50) # Use triples_by_subject +def get_s(self, collection, s, limit=10) # Use triples_by_subject +def get_p(self, collection, p, limit=10) # Use triples_by_po +def get_o(self, collection, o, limit=10) # Use triples_by_object +def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject +def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!) +def get_os(self, collection, o, s, limit=10) # Use triples_by_subject +def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject + +# Collection management +def delete_collection(self, collection) -> None # Delete from all three tables +``` + +#### Archivos de Integración (No se requieren cambios en la lógica) + +**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`** +No se necesitan cambios: utiliza la API KnowledgeGraph existente. +Se beneficia automáticamente de las mejoras de rendimiento. + +**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`** +No se necesitan cambios: utiliza la API KnowledgeGraph existente. +Se beneficia automáticamente de las mejoras de rendimiento. + +### Archivos de Prueba que Requieren Actualizaciones + +#### Pruebas Unitarias +**`tests/unit/test_storage/test_triples_cassandra_storage.py`** +Actualizar las expectativas de las pruebas para los cambios en el esquema. +Agregar pruebas para la consistencia de múltiples tablas. +Verificar que no haya "ALLOW FILTERING" en los planes de consulta. + +**`tests/unit/test_query/test_triples_cassandra_query.py`** +Actualizar las aserciones de rendimiento. +Probar los 8 patrones de consulta contra las nuevas tablas. +Verificar el enrutamiento de consultas a las tablas correctas. + +#### Pruebas de Integración +**`tests/integration/test_cassandra_integration.py`** +Pruebas de extremo a extremo con el nuevo esquema. +Comparaciones de referencia de rendimiento. +Verificación de la consistencia de los datos en todas las tablas. + +**`tests/unit/test_storage/test_cassandra_config_integration.py`** +Actualizar las pruebas de validación de esquema. +Probar escenarios de migración. + +### Estrategia de Implementación + +#### Fase 1: Esquema y Métodos Centrales +1. **Reescribir el método `init()`** - Crear cuatro tablas en lugar de una. +2. **Reescribir el método `insert()`** - Escrituras por lotes a las cuatro tablas. +3. **Implementar sentencias preparadas** - Para un rendimiento óptimo. +4. **Agregar lógica de enrutamiento de tablas** - Dirigir las consultas a las tablas óptimas. +5. **Implementar la eliminación de colecciones** - Leer de triples_collection, eliminar por lotes de todas las tablas. + +#### Fase 2: Optimización de Métodos de Consulta +1. **Reescribir cada método get_*** para usar la tabla óptima. +2. **Eliminar todo el uso de ALLOW FILTERING**. +3. **Implementar el uso eficiente de la clave de clustering**. +4. **Agregar registro del rendimiento de las consultas**. + +#### Fase 3: Gestión de Colecciones +1. **Actualizar `delete_collection()`** - Eliminar de las tres tablas. +2. **Agregar verificación de consistencia** - Asegurar que todas las tablas se mantengan sincronizadas. +3. **Implementar operaciones por lotes** - Para operaciones multi-tabla atómicas. + +### Detalles Clave de la Implementación + +#### Estrategia de Escritura por Lotes +```python +def insert(self, collection, s, p, o): + batch = BatchStatement() + + # Insert into all four tables + batch.add(self.insert_subject_stmt, (collection, s, p, o)) + batch.add(self.insert_po_stmt, (collection, p, o, s)) + batch.add(self.insert_object_stmt, (collection, o, s, p)) + batch.add(self.insert_collection_stmt, (collection, s, p, o)) + + self.session.execute(batch) +``` + +#### Lógica de enrutamiento de consultas +```python +def get_po(self, collection, p, o, limit=10): + # Route to triples_p table - NO ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) + +def get_spo(self, collection, s, p, o, limit=10): + # Route to triples_collection table for exact SPO lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) +``` + +#### Lógica de eliminación de colecciones +```python +def delete_collection(self, collection): + # Step 1: Read all triples from collection table + rows = self.session.execute( + f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s", + (collection,) + ) + + # Step 2: Batch delete from all 4 tables + batch = BatchStatement() + count = 0 + + for row in rows: + s, p, o = row.s, row.p, row.o + + # Delete using full partition keys for each table + batch.add(SimpleStatement( + f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?" + ), (collection, p, o, s)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?" + ), (collection, o, s, p)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + count += 1 + + # Execute every 100 triples to avoid oversized batches + if count % 100 == 0: + self.session.execute(batch) + batch = BatchStatement() + + # Execute remaining deletions + if count % 100 != 0: + self.session.execute(batch) + + logger.info(f"Deleted {count} triples from collection {collection}") +``` + +#### Optimización de sentencias preparadas +```python +def prepare_statements(self): + # Cache prepared statements for better performance + self.insert_subject_stmt = self.session.prepare( + f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + self.insert_po_stmt = self.session.prepare( + f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)" + ) + self.insert_object_stmt = self.session.prepare( + f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)" + ) + self.insert_collection_stmt = self.session.prepare( + f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + # ... query statements +``` + +## Estrategia de Migración + +### Enfoque de Migración de Datos + +#### Opción 1: Despliegue Blue-Green (Recomendado) +1. **Implementar el nuevo esquema junto con el existente** - Utilizar nombres de tabla diferentes temporalmente +2. **Período de escritura dual** - Escribir tanto en el esquema antiguo como en el nuevo durante la transición +3. **Migración en segundo plano** - Copiar los datos existentes a las nuevas tablas +4. **Cambiar las lecturas** - Dirigir las consultas a las nuevas tablas una vez que los datos se hayan migrado +5. **Eliminar las tablas antiguas** - Después del período de verificación + +#### Opción 2: Migración In-Place +1. **Adición de esquema** - Crear nuevas tablas en el keyspace existente +2. **Script de migración de datos** - Copia por lotes de la tabla antigua a las nuevas tablas +3. **Actualización de la aplicación** - Implementar el nuevo código después de que se complete la migración +4. **Limpieza de la tabla antigua** - Eliminar la tabla antigua e índices + +### Compatibilidad hacia atrás + +#### Estrategia de Despliegue +```python +# Environment variable to control table usage during migration +USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' + +class KnowledgeGraph: + def __init__(self, ...): + if USE_LEGACY_TABLES: + self.init_legacy_schema() + else: + self.init_optimized_schema() +``` + +#### Script de Migración +```python +def migrate_data(): + # Read from old table + old_triples = session.execute("SELECT collection, s, p, o FROM triples") + + # Batch write to new tables + for batch in batched(old_triples, 100): + batch_stmt = BatchStatement() + for row in batch: + # Add to all three new tables + batch_stmt.add(insert_subject_stmt, row) + batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s)) + batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p)) + session.execute(batch_stmt) +``` + +### Estrategia de Validación + +#### Comprobaciones de Consistencia de Datos +```python +def validate_migration(): + # Count total records in old vs new tables + old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,)) + new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,)) + + assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}" + + # Spot check random samples + sample_queries = generate_test_queries() + for query in sample_queries: + old_result = execute_legacy_query(query) + new_result = execute_optimized_query(query) + assert old_result == new_result, f"Query results differ for {query}" +``` + +## Estrategia de Pruebas + +### Pruebas de Rendimiento + +#### Escenarios de Referencia +1. **Comparación del Rendimiento de Consultas** + Métricas de rendimiento antes y después para los 8 tipos de consultas + Centrarse en la mejora del rendimiento de get_po (eliminar ALLOW FILTERING) + Medir la latencia de las consultas bajo varios tamaños de datos + +2. **Pruebas de Carga** + Ejecución concurrente de consultas + Rendimiento de escritura con operaciones por lotes + Utilización de memoria y CPU + +3. **Pruebas de Escalabilidad** + Rendimiento con tamaños de colección crecientes + Distribución de consultas de múltiples colecciones + Utilización de nodos del clúster + +#### Conjuntos de Datos de Prueba +**Pequeño:** 10K triples por colección +**Mediano:** 100K triples por colección +**Grande:** 1M+ triples por colección +**Múltiples colecciones:** Probar la distribución de particiones + +### Pruebas Funcionales + +#### Actualizaciones de Pruebas Unitarias +```python +# Example test structure for new implementation +class TestCassandraKGPerformance: + def test_get_po_no_allow_filtering(self): + # Verify get_po queries don't use ALLOW FILTERING + with patch('cassandra.cluster.Session.execute') as mock_execute: + kg.get_po('test_collection', 'predicate', 'object') + executed_query = mock_execute.call_args[0][0] + assert 'ALLOW FILTERING' not in executed_query + + def test_multi_table_consistency(self): + # Verify all tables stay in sync + kg.insert('test', 's1', 'p1', 'o1') + + # Check all tables contain the triple + assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1') + assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1') + assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1') +``` + +#### Actualizaciones de la prueba de integración +```python +class TestCassandraIntegration: + def test_query_performance_regression(self): + # Ensure new implementation is faster than old + old_time = benchmark_legacy_get_po() + new_time = benchmark_optimized_get_po() + assert new_time < old_time * 0.5 # At least 50% improvement + + def test_end_to_end_workflow(self): + # Test complete write -> query -> delete cycle + # Verify no performance degradation in integration +``` + +### Plan de Reversión + +#### Estrategia de Reversión Rápida +1. **Alternancia de variables de entorno** - Vuelva a las tablas heredadas inmediatamente. +2. **Mantenga las tablas heredadas** - No las elimine hasta que se demuestre el rendimiento. +3. **Alertas de monitoreo** - Desencadenadores de reversión automatizados basados en tasas de error/latencia. + +#### Validación de la Reversión +```python +def rollback_to_legacy(): + # Set environment variable + os.environ['CASSANDRA_USE_LEGACY'] = 'true' + + # Restart services to pick up change + restart_cassandra_services() + + # Validate functionality + run_smoke_tests() +``` + +## Riesgos y Consideraciones + +### Riesgos de Rendimiento +**Aumento de la latencia de escritura** - 4 operaciones de escritura por inserción (un 33% más que el enfoque de 3 tablas) +**Sobrecarga de almacenamiento** - 4 veces más espacio de almacenamiento requerido (un 33% más que el enfoque de 3 tablas) +**Fallos en la escritura por lotes** - Se necesita un manejo adecuado de errores +**Complejidad de la eliminación** - La eliminación de la colección requiere un bucle de lectura y eliminación + +### Riesgos Operacionales +**Complejidad de la migración** - Migración de datos para conjuntos de datos grandes +**Desafíos de consistencia** - Asegurar que todas las tablas permanezcan sincronizadas +**Lagunas de monitoreo** - Se necesitan nuevas métricas para las operaciones de múltiples tablas + +### Estrategias de Mitigación +1. **Implementación gradual** - Comenzar con colecciones pequeñas +2. **Monitoreo integral** - Realizar un seguimiento de todas las métricas de rendimiento +3. **Validación automatizada** - Verificación continua de la consistencia +4. **Capacidad de reversión rápida** - Selección de tablas basada en el entorno + +## Criterios de Éxito + +### Mejoras de Rendimiento +[ ] **Eliminar ALLOW FILTERING** - Las consultas get_po y get_os se ejecutan sin filtrado +[ ] **Reducción de la latencia de la consulta** - Mejora del 50% o más en los tiempos de respuesta de las consultas +[ ] **Mejor distribución de la carga** - Sin particiones "calientes", distribución uniforme de la carga en los nodos del clúster +[ ] **Rendimiento escalable** - El tiempo de consulta es proporcional al tamaño del resultado, no a la cantidad total de datos + +### Requisitos Funcionales +[ ] **Compatibilidad de la API** - Todo el código existente continúa funcionando sin cambios +[ ] **Consistencia de datos** - Las tres tablas permanecen sincronizadas +[ ] **Cero pérdida de datos** - La migración preserva todas las triples existentes +[ ] **Compatibilidad con versiones anteriores** - Capacidad de volver al esquema heredado + +### Requisitos Operacionales +[ ] **Migración segura** - Implementación blue-green con capacidad de reversión +[ ] **Cobertura de monitoreo** - Métricas integrales para operaciones de múltiples tablas +[ ] **Cobertura de pruebas** - Todos los patrones de consulta se prueban con puntos de referencia de rendimiento +[ ] **Documentación** - Procedimientos de implementación y operación actualizados + +## Cronograma + +### Fase 1: Implementación +[ ] Reescribir `cassandra_kg.py` con el esquema de múltiples tablas +[ ] Implementar operaciones de escritura por lotes +[ ] Agregar optimización de sentencias preparadas +[ ] Actualizar pruebas unitarias + +### Fase 2: Pruebas de Integración +[ ] Actualizar pruebas de integración +[ ] Pruebas de rendimiento +[ ] Pruebas de carga con volúmenes de datos realistas +[ ] Scripts de validación para la consistencia de los datos + +### Fase 3: Planificación de la Migración +[ ] Scripts de implementación blue-green +[ ] Herramientas de migración de datos +[ ] Actualizaciones del panel de monitoreo +[ ] Procedimientos de reversión + +### Fase 4: Despliegue en Producción +[ ] Implementación gradual en producción +[ ] Monitoreo y validación del rendimiento +[ ] Limpieza de tablas heredadas +[ ] Actualizaciones de la documentación + +## Conclusión + +Esta estrategia de desnormalización de múltiples tablas aborda directamente los dos cuellos de botella de rendimiento críticos: + +1. **Elimina el costoso ALLOW FILTERING** al proporcionar estructuras de tabla óptimas para cada patrón de consulta +2. **Mejora la eficacia de la agrupación** a través de claves de partición compuestas que distribuyen la carga de manera adecuada + +El enfoque aprovecha las fortalezas de Cassandra al tiempo que mantiene la compatibilidad total de la API, lo que garantiza que el código existente se beneficie automáticamente de las mejoras de rendimiento. diff --git a/docs/tech-specs/cassandra-performance-refactor.he.md b/docs/tech-specs/cassandra-performance-refactor.he.md new file mode 100644 index 00000000..c380a34d --- /dev/null +++ b/docs/tech-specs/cassandra-performance-refactor.he.md @@ -0,0 +1,679 @@ +# מפרט טכני: שיפור ביצועים של בסיס הידע Cassandra + +**סטטוס:** טיוטה +**כותב:** עוזר +**תאריך:** 2025-09-18 + +## סקירה כללית + +מפרט זה עוסק בבעיות ביצועים ביישום בסיס הידע Cassandra של TrustGraph ומציע אופטימיזציות לאחסון ושליפה של משולשות RDF. + +## יישום נוכחי + +### עיצוב הסכימה + +היישום הנוכחי משתמש בעיצוב טבלה יחידה ב-`trustgraph-flow/trustgraph/direct/cassandra_kg.py`: + +```sql +CREATE TABLE triples ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` + +**אינדקסים משניים:** +`triples_s` על `s` (נושא) +`triples_p` על `p` (נשוא) +`triples_o` על `o` (אובייקט) + +### תבניות שאילתה + +המימוש הנוכחי תומך ב-8 תבניות שאילתה מובחנות: + +1. **get_all(collection, limit=50)** - שליפה של כל השלשות עבור אוסף + ```sql + SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50 + ``` + +2. **get_s(collection, s, limit=10)** - שאילתה לפי נושא. + ```sql + SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10 + ``` + +3. **get_p(collection, p, limit=10)** - שאילתה לפי תנאי. + ```sql + SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10 + ``` + +4. **get_o(collection, o, limit=10)** - שאילתה לפי אובייקט. + ```sql + SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10 + ``` + +5. **get_sp(collection, s, p, limit=10)** - שאילתה לפי נושא + טענה + ```sql + SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10 + ``` + +6. **get_po(collection, p, o, limit=10)** - שאילתה לפי תנאי + אובייקט ⚠️ + ```sql + SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING + ``` + +7. **get_os(collection, o, s, limit=10)** - שאילתה לפי אובייקט + נושא ⚠️ + ```sql + SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING + ``` + +8. **get_spo(collection, s, p, o, limit=10)** - התאמה מדויקת לשלושה חלקים (subject, predicate, object). + ```sql + SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10 + ``` + +### ארכיטקטורה נוכחית + +**קובץ: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`** +מחלקה יחידה `KnowledgeGraph` המטפלת בכל הפעולות +בריכת חיבורים באמצעות רשימה גלובלית `_active_clusters` +שם טבלה קבוע: `"triples"` +מרחב מפתחות לכל מודל משתמש +שכפול SimpleStrategy עם גורם 1 + +**נקודות אינטגרציה:** +**נתיב כתיבה:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +**נתיב שאילתה:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` +**מאגר ידע:** `trustgraph-flow/trustgraph/tables/knowledge.py` + +## בעיות ביצועים שזוהו + +### בעיות ברמת הסכימה + +1. **עיצוב מפתח ראשי לא יעיל** + נוכחי: `PRIMARY KEY (collection, s, p, o)` + גורם לקיבוץ לקוי עבור דפוסי גישה נפוצים + מחייב שימוש באינדקסים משניים יקרים + +2. **שימוש יתר באינדקסים משניים** ⚠️ + שלושה אינדקסים משניים על עמודות עם קרדינליות גבוהה (s, p, o) + אינדקסים משניים ב-Cassandra הם יקרים ואינם מתאימים להרחבה + שאילתות 6 ו-7 דורשות `ALLOW FILTERING` המצביע על מודל נתונים לקוי + +3. **סיכון לחלוקות חמות** + מפתח חלוקה יחיד `collection` יכול ליצור חלוקות חמות + אוספים גדולים יתרכזו בצמתים בודדים + אין אסטרטגיית חלוקה לאיזון עומסים + +### בעיות ברמת השאילתה + +1. **שימוש ב-ALLOW FILTERING** ⚠️ + שני סוגי שאילתות (get_po, get_os) דורשים `ALLOW FILTERING` + שאילתות אלו סורקות מספר חלוקות ויקרות מאוד + הביצועים יורדים באופן ליניארי עם גודל הנתונים + +2. **דפוסי גישה לא יעילים** + אין אופטימיזציה עבור דפוסי שאילתות RDF נפוצים + חסרים אינדקסים מורכבים עבור שילובים תכופים של שאילתות + אין התחשבות בדפוסי מעבר גרפים + +3. **חוסר באופטימיזציה של שאילתות** + אין שמירת מטמון של הצהרות מוכנות + אין רמזים או אסטרטגיות אופטימיזציה לשאילתות + אין התחשבות בדף אחרי דף מעבר לפונקציית LIMIT פשוטה + +## הצהרת בעיה + +ליישום בסיס הידע הנוכחי של Cassandra ישנם שני צווארי בקבוק ביצועים קריטיים: + +### 1. ביצועים לא יעילים של שאילתת get_po + +השאילתה `get_po(collection, p, o)` אינה יעילה מאוד מכיוון שהיא דורשת `ALLOW FILTERING`: + +```sql +SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING +``` + +**מדוע זה בעייתי:** +`ALLOW FILTERING` גורם לקסנדרה לסרוק את כל המחיצות בתוך האוסף. +הביצועים יורדים באופן ליניארי עם גודל הנתונים. +זהו דפוס שאילתות RDF נפוץ (מציאת נושאים שיש להם קשר ספציפי של נשוא-פועל-מושא). +זה יוצר עומס משמעותי על האשכול ככל שהנתונים גדלים. + +### 2. אסטרטגיית קיבוץ לקויה + +המפתח הראשי הנוכחי `PRIMARY KEY (collection, s, p, o)` מספק יתרונות קיבוץ מינימליים: + +**בעיות עם הקיבוץ הנוכחי:** +`collection` כמפתח מחיצה לא מפזר את הנתונים בצורה יעילה. +רוב האוספים מכילים נתונים מגוונים, מה שהופך את הקיבוץ ללא יעיל. +אין התחשבות בדפוסי גישה נפוצים בשאילתות RDF. +אוספים גדולים יוצרים מחיצות "חמות" על צמתים בודדים. +עמודות הקיבוץ (s, p, o) אינן מייעלות עבור דפוסי מעבר גרפים טיפוסיים. + +**השפעה:** +שאילתות אינן נהנות ממיקום נתונים. +ניצולת מטמון לקויה. +חלוקת עומסים לא אחידה בין צמתי האשכול. +צווארי בקבוק של יכולת הרחבה ככל שהאוספים גדלים. + +## פתרון מוצע: אסטרטגיית דה-נורמליזציה של 4 טבלאות + +### סקירה כללית + +החליפו את הטבלה הבודדת `triples` בארבע טבלאות ייעודיות, כל אחת מותאמת לדפוסי שאילתות ספציפיים. זה מבטל את הצורך באינדקסים משניים וב-ALLOW FILTERING תוך מתן ביצועים אופטימליים לכל סוגי השאילתות. הטבלה הרביעית מאפשרת מחיקת אוספים יעילה למרות מפתחות מחיצה מורכבים. + +### עיצוב סכימה חדש + +**טבלה 1: שאילתות ממוקדות בנושא (triples_s)** +```sql +CREATE TABLE triples_s ( + collection text, + s text, + p text, + o text, + PRIMARY KEY ((collection, s), p, o) +); +``` +**משפר:** get_s, get_sp, get_os +**מפתח מחיצה:** (collection, s) - פיזור טוב יותר מאשר רק collection +**קיבוץ:** (p, o) - מאפשר חיפושים יעילים של טווחים/אובייקטים עבור נושא + +**טבלה 2: שאילתות של טריפלטים (predicate-object) (triples_p)** +```sql +CREATE TABLE triples_p ( + collection text, + p text, + o text, + s text, + PRIMARY KEY ((collection, p), o, s) +); +``` +**משפר:** get_p, get_po (מבטל את ALLOW FILTERING!) +**מפתח מחיצה:** (collection, p) - גישה ישירה באמצעות תנאי +**קיבוץ:** (o, s) - מעבר יעיל בין אובייקט לנושא + +**טבלה 3: שאילתות ממוקדות אובייקט (triples_o)** +```sql +CREATE TABLE triples_o ( + collection text, + o text, + s text, + p text, + PRIMARY KEY ((collection, o), s, p) +); +``` +**אופטימיזציה:** get_o +**מפתח מחיצה:** (collection, o) - גישה ישירה באמצעות אובייקט +**קיבוץ:** (s, p) - מעבר יעיל בין נושא ופועל + +**טבלה 4: ניהול אוספים ושאילתות SPO (triples_collection)** +```sql +CREATE TABLE triples_collection ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` +**אופטימיזציה:** get_spo, delete_collection +**מפתח מחיצה:** רק אוסף - מאפשר פעולות יעילות ברמת האוסף. +**קיבוץ:** (s, p, o) - סדר משולש סטנדרטי. +**מטרה:** שימוש כפול לחיפושים מדויקים של SPO וגם כמדד למחיקה. + +### מיפוי שאילתות + +| שאילתה מקורית | טבלה יעד | שיפור ביצועים | +|----------------|-------------|------------------------| +| get_all(collection) | triples_s | ALLOW FILTERING (מתאים לסריקה) | +| get_s(collection, s) | triples_s | גישה ישירה למחיצה | +| get_p(collection, p) | triples_p | גישה ישירה למחיצה | +| get_o(collection, o) | triples_o | גישה ישירה למחיצה | +| get_sp(collection, s, p) | triples_s | מחיצה + קיבוץ | +| get_po(collection, p, o) | triples_p | **אין יותר ALLOW FILTERING!** | +| get_os(collection, o, s) | triples_o | מחיצה + קיבוץ | +| get_spo(collection, s, p, o) | triples_collection | חיפוש מפתח מדויק | +| delete_collection(collection) | triples_collection | קריאת מדד, מחיקה אצווה של הכל | + +### אסטרטגיית מחיקת אוסף + +עם מפתחות מחיצה מורכבים, אי אפשר פשוט לבצע `DELETE FROM table WHERE collection = ?`. במקום זאת: + +1. **שלב קריאה:** שאילתא `triples_collection` כדי לרשום את כל המשולשים: + ```sql + SELECT s, p, o FROM triples_collection WHERE collection = ? + ``` + זה יעיל מכיוון ש-`collection` הוא מפתח החלוקה עבור הטבלה הזו. + +2. **שלב המחיקה:** עבור כל שלישייה (s, p, o), מחקו מכל 4 הטבלאות תוך שימוש במפתחות חלוקה מלאים: + ```sql + DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ? + DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ? + DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ? + DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ? + ``` + מחולק לקבוצות של 100 רשומות לטובת יעילות. + +**ניתוח פשרות:** +✅ שומר על ביצועי שאילתות אופטימליים עם מחיצות מבוזרות. +✅ אין מחיצות עמוסות עבור אוספים גדולים. +❌ לוגיקת מחיקה מורכבת יותר (קריאה ואז מחיקה). +❌ זמן מחיקה תלוי בגודל האוסף. + +### יתרונות + +1. **מבטל את ALLOW FILTERING** - לכל שאילתה יש נתיב גישה אופטימלי (מלבד סריקת get_all). +2. **ללא אינדקסים משניים** - כל טבלה היא האינדקס לדפוס השאילתה שלה. +3. **הפצת נתונים טובה יותר** - מפתחות מחיצה מורכבים מפזרים את העומס בצורה יעילה. +4. **ביצועים צפויים** - זמן שאילתה תלוי בגודל התוצאה, ולא בגודל הנתונים הכולל. +5. **מנצל את החוזקות של Cassandra** - תוכנן עבור ארכיטקטורת Cassandra. +6. **מאפשר מחיקת אוספים** - triples_collection משמש כמחירון מחיקה. + +## תוכנית יישום + +### קבצים הדורשים שינוי + +#### קובץ יישום ראשי + +**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - נדרש כתיבה מחדש מלאה. + +**שיטות שיש לשכתב:** +```python +# Schema initialization +def init(self) -> None # Replace single table with three tables + +# Insert operations +def insert(self, collection, s, p, o) -> None # Write to all three tables + +# Query operations (API unchanged, implementation optimized) +def get_all(self, collection, limit=50) # Use triples_by_subject +def get_s(self, collection, s, limit=10) # Use triples_by_subject +def get_p(self, collection, p, limit=10) # Use triples_by_po +def get_o(self, collection, o, limit=10) # Use triples_by_object +def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject +def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!) +def get_os(self, collection, o, s, limit=10) # Use triples_by_subject +def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject + +# Collection management +def delete_collection(self, collection) -> None # Delete from all three tables +``` + +#### קבצי אינטגרציה (אין צורך בשינויים לוגיים) + +**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`** +אין צורך בשינויים - משתמשים ב-API של KnowledgeGraph הקיים +נהנים אוטומטית משיפורי ביצועים + +**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`** +אין צורך בשינויים - משתמשים ב-API של KnowledgeGraph הקיים +נהנים אוטומטית משיפורי ביצועים + +### קבצי בדיקה הדורשים עדכונים + +#### בדיקות יחידה +**`tests/unit/test_storage/test_triples_cassandra_storage.py`** +עדכון ציפיות הבדיקה עבור שינויים בסכימה +הוספת בדיקות עבור עקביות בין טבלאות מרובות +אימות היעדר ALLOW FILTERING בתוכניות שאילתות + +**`tests/unit/test_query/test_triples_cassandra_query.py`** +עדכון טענות ביצועים +בדיקת כל 8 דפוסי השאילתות מול טבלאות חדשות +אימות ניתוב השאילתות לטבלאות הנכונות + +#### בדיקות אינטגרציה +**`tests/integration/test_cassandra_integration.py`** +בדיקות מקצה לקצה עם סכימה חדשה +השוואות ביצועים +אימות עקביות נתונים בין טבלאות + +**`tests/unit/test_storage/test_cassandra_config_integration.py`** +עדכון בדיקות אימות סכימה +בדיקת תרחישי מעבר + +### אסטרטגיית יישום + +#### שלב 1: סכימה ושיטות ליבה +1. **כתיבת מחדש של `init()`** - יצירת ארבע טבלאות במקום אחת +2. **כתיבת מחדש של `insert()`** - כתיבה באצווה לכל ארבע הטבלאות +3. **יישום הצהרות מוכנות** - לביצועים אופטימליים +4. **הוספת לוגיקת ניתוב טבלאות** - הפניית שאילתות לטבלאות האופטימליות +5. **יישום מחיקת אוספים** - קריאה מ-triples_collection, מחיקה באצווה מכל הטבלאות + +#### שלב 2: אופטימיזציה של שיטות שאילתה +1. **כתיבת מחדש של כל שיטת get_*** לשימוש בטבלה האופטימלית +2. **הסרת כל השימושים ב-ALLOW FILTERING** +3. **יישום שימוש יעיל במפתח מיון** +4. **הוספת רישום ביצועי שאילתות** + +#### שלב 3: ניהול אוספים +1. **עדכון `delete_collection()`** - הסרה מכל שלושת הטבלאות +2. **הוספת אימות עקביות** - הבטחת סנכרון בין כל הטבלאות +3. **יישום פעולות באצווה** - לפעולות מרובות טבלאות אטומיות + +### פרטי יישום מרכזיים + +#### אסטרטגיית כתיבה באצווה +```python +def insert(self, collection, s, p, o): + batch = BatchStatement() + + # Insert into all four tables + batch.add(self.insert_subject_stmt, (collection, s, p, o)) + batch.add(self.insert_po_stmt, (collection, p, o, s)) + batch.add(self.insert_object_stmt, (collection, o, s, p)) + batch.add(self.insert_collection_stmt, (collection, s, p, o)) + + self.session.execute(batch) +``` + +#### לוגיקת ניתוב שאילתות +```python +def get_po(self, collection, p, o, limit=10): + # Route to triples_p table - NO ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) + +def get_spo(self, collection, s, p, o, limit=10): + # Route to triples_collection table for exact SPO lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) +``` + +#### לוגיקת מחיקת אוספים +```python +def delete_collection(self, collection): + # Step 1: Read all triples from collection table + rows = self.session.execute( + f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s", + (collection,) + ) + + # Step 2: Batch delete from all 4 tables + batch = BatchStatement() + count = 0 + + for row in rows: + s, p, o = row.s, row.p, row.o + + # Delete using full partition keys for each table + batch.add(SimpleStatement( + f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?" + ), (collection, p, o, s)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?" + ), (collection, o, s, p)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + count += 1 + + # Execute every 100 triples to avoid oversized batches + if count % 100 == 0: + self.session.execute(batch) + batch = BatchStatement() + + # Execute remaining deletions + if count % 100 != 0: + self.session.execute(batch) + + logger.info(f"Deleted {count} triples from collection {collection}") +``` + +#### אופטימיזציה של הצהרת הכנה (Prepared Statement) +```python +def prepare_statements(self): + # Cache prepared statements for better performance + self.insert_subject_stmt = self.session.prepare( + f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + self.insert_po_stmt = self.session.prepare( + f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)" + ) + self.insert_object_stmt = self.session.prepare( + f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)" + ) + self.insert_collection_stmt = self.session.prepare( + f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + # ... query statements +``` + +## אסטרטגיית מעבר + +### גישת מעבר נתונים + +#### אפשרות 1: פריסה בצבע כחול-ירוק (מומלץ) +1. **פריסת הסכימה החדשה לצד הקיימת** - השתמש בשמות טבלאות שונים באופן זמני +2. **תקופת כתיבה כפולה** - כתיבה גם לסכימה הישנה וגם לחדשה במהלך המעבר +3. **מעבר נתונים ברקע** - העתקת נתונים קיימים לטבלאות חדשות +4. **הפניית שאילתות** - הפניית שאילתות לטבלאות החדשות לאחר שהנתונים עברו +5. **מחיקת הטבלאות הישנות** - לאחר תקופת אימות + +#### אפשרות 2: מעבר במקום +1. **הוספת סכימה** - יצירת טבלאות חדשות במרחב מפתחות קיים +2. **סקריפט מעבר נתונים** - העתקה באצווה מטבלה ישנה לטבלאות חדשות +3. **עדכון יישום** - פריסת קוד חדש לאחר השלמת המעבר +4. **ניקוי הטבלה הישנה** - הסרת הטבלה הישנה והאינדקסים + +### תאימות לאחור + +#### אסטרטגיית פריסה +```python +# Environment variable to control table usage during migration +USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' + +class KnowledgeGraph: + def __init__(self, ...): + if USE_LEGACY_TABLES: + self.init_legacy_schema() + else: + self.init_optimized_schema() +``` + +#### סקריפט הגירה +```python +def migrate_data(): + # Read from old table + old_triples = session.execute("SELECT collection, s, p, o FROM triples") + + # Batch write to new tables + for batch in batched(old_triples, 100): + batch_stmt = BatchStatement() + for row in batch: + # Add to all three new tables + batch_stmt.add(insert_subject_stmt, row) + batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s)) + batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p)) + session.execute(batch_stmt) +``` + +### אסטרטגיית אימות + +#### בדיקות עקביות נתונים +```python +def validate_migration(): + # Count total records in old vs new tables + old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,)) + new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,)) + + assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}" + + # Spot check random samples + sample_queries = generate_test_queries() + for query in sample_queries: + old_result = execute_legacy_query(query) + new_result = execute_optimized_query(query) + assert old_result == new_result, f"Query results differ for {query}" +``` + +## אסטרטגיית בדיקות + +### בדיקות ביצועים + +#### תרחישי ביצוע +1. **השוואת ביצועי שאילתות** + מדדי ביצועים לפני ואחרי עבור כל 8 סוגי השאילתות + התמקדות בשיפור ביצועים של שאילתת get_po (הסרת ALLOW FILTERING) + מדידת השהייה של שאילתות בתנאי גדלי נתונים שונים + +2. **בדיקות עומסים** + ביצוע שאילתות במקביל + קצב כתיבה עם פעולות אצווה + ניצול זיכרון ו-CPU + +3. **בדיקות סקלאביליות** + ביצועים עם גדלי אוספים גדלים + חלוקת שאילתות בין אוספים מרובים + ניצול צמתים באשכול + +#### סטי נתוני בדיקה +**קטן:** 10 אלף משולשים לאוסף +**בינוני:** 100 אלף משולשים לאוסף +**גדול:** 1 מיליון+ משולשים לאוסף +**אוספים מרובים:** בדיקת חלוקת מחיצות + +### בדיקות פונקציונליות + +#### עדכוני בדיקות יחידה +```python +# Example test structure for new implementation +class TestCassandraKGPerformance: + def test_get_po_no_allow_filtering(self): + # Verify get_po queries don't use ALLOW FILTERING + with patch('cassandra.cluster.Session.execute') as mock_execute: + kg.get_po('test_collection', 'predicate', 'object') + executed_query = mock_execute.call_args[0][0] + assert 'ALLOW FILTERING' not in executed_query + + def test_multi_table_consistency(self): + # Verify all tables stay in sync + kg.insert('test', 's1', 'p1', 'o1') + + # Check all tables contain the triple + assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1') + assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1') + assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1') +``` + +#### עדכונים לבדיקות אינטגרציה +```python +class TestCassandraIntegration: + def test_query_performance_regression(self): + # Ensure new implementation is faster than old + old_time = benchmark_legacy_get_po() + new_time = benchmark_optimized_get_po() + assert new_time < old_time * 0.5 # At least 50% improvement + + def test_end_to_end_workflow(self): + # Test complete write -> query -> delete cycle + # Verify no performance degradation in integration +``` + +### תוכנית חזרה אחורה + +#### אסטרטגיה מהירה לחזרה אחורה +1. **החלפת משתנה סביבה** - חזרה מיידית לטבלאות הישנות. +2. **שמירה על הטבלאות הישנות** - לא למחוק עד שיוכח שיפור בביצועים. +3. **התראות ניטור** - הפעלת חזרה אוטומטית בהתבסס על שיעורי שגיאות/השהייה. + +#### אימות חזרה אחורה +```python +def rollback_to_legacy(): + # Set environment variable + os.environ['CASSANDRA_USE_LEGACY'] = 'true' + + # Restart services to pick up change + restart_cassandra_services() + + # Validate functionality + run_smoke_tests() +``` + +## סיכונים ושיקולים + +### סיכוני ביצועים +**עלייה בלעדי כתיבה** - 4 פעולות כתיבה לכל הוספה (33% יותר מהגישה של 3 טבלאות) +**תקורת אחסון** - דרישת אחסון של 4x (33% יותר מהגישה של 3 טבלאות) +**כשלים בכתיבה אצווה** - יש צורך בטיפול תקין בשגיאות +**מורכבות מחיקה** - מחיקת אוסף דורשת לולאה של קריאה ולאחר מכן מחיקה + +### סיכונים תפעוליים +**מורכבות העברה** - העברת נתונים עבור מערכי נתונים גדולים +**אתגרים של עקביות** - הבטחת סנכרון של כל הטבלאות +**פערים בניטור** - יש צורך במדדים חדשים עבור פעולות מרובות טבלאות + +### אסטרטגיות הפחתת סיכונים +1. **פריסה הדרגתית** - התחילו עם אוספים קטנים +2. **ניטור מקיף** - מעקב אחר כל מדדי הביצועים +3. **אימות אוטומטי** - בדיקת עקביות רציפה +4. **יכולת ביטול מהירה** - בחירת טבלה מבוססת סביבה + +## קריטריוני הצלחה + +### שיפורי ביצועים +[ ] **ביטול ALLOW FILTERING** - שאילתות get_po ו-get_os פועלות ללא סינון +[ ] **הפחתת השהייה בשאילתות** - שיפור של 50%+ בזמני תגובה של שאילתות +[ ] **חלוקת עומסים טובה יותר** - ללא מחיצות "חמות", חלוקת עומסים שווה על פני צמתים בקלאסטר +[ ] **ביצועים ניתנים להרחבה** - זמן שאילתה תלוי בגודל התוצאה, ולא בנפח הנתונים הכולל + +### דרישות פונקציונליות +[ ] **תאימות API** - כל הקוד הקיים ממשיך לעבוד ללא שינוי +[ ] **עקביות נתונים** - שלוש הטבלאות נשארות מסונכרנות +[ ] **אפס אובדן נתונים** - העברה שומרת על כל הטרפלים הקיימים +[ ] **תאימות לאחור** - אפשרות לחזור לסקמה הישנה + +### דרישות תפעוליות +[ ] **העברה בטוחה** - פריסה בצורה כחולה-ירוקה עם יכולת ביטול +[ ] **כיסוי ניטור** - מדדים מקיפים עבור פעולות מרובות טבלאות +[ ] **כיסוי בדיקות** - כל דפוסי השאילתות נבדקו עם מדדי ביצועים +[ ] **תיעוד** - עדכון נהלי פריסה ותפעול + +## ציר זמן + +### שלב 1: יישום +[ ] כתיבה מחדש של `cassandra_kg.py` עם סכימת טבלאות מרובות +[ ] יישום פעולות כתיבה אצווה +[ ] הוספת אופטימיזציה של הצהרות מוכנות +[ ] עדכון בדיקות יחידה + +### שלב 2: בדיקות אינטגרציה +[ ] עדכון בדיקות אינטגרציה +[ ] מדידת ביצועים +[ ] בדיקת עומסים עם נפחי נתונים ריאליים +[ ] סקריפטים לאימות עקביות נתונים + +### שלב 3: תכנון העברה +[ ] סקריפטים לפריסה בצורה כחולה-ירוקה +[ ] כלים להעברת נתונים +[ ] עדכוני לוח מחוונים לניטור +[ ] נהלי ביטול + +### שלב 4: פריסה לייצור +[ ] פריסה הדרגתית לסביבת ייצור +[ ] ניטור ואימות ביצועים +[ ] ניקוי טבלאות ישנות +[ ] עדכוני תיעוד + +## מסקנה + +אסטרטגיית הדה-נורמליזציה מרובת טבלאות פותרת ישירות את שני צווארי הבקבוק הקריטיים בביצועים: + +1. **מבטלת את ALLOW FILTERING היקר** על ידי מתן מבני טבלאות אופטימליים עבור כל דפוס שאילתה +2. **משפרת את יעילות הקיבוץ** באמצעות מפתחות מחיצה מורכבים שמפיצים את העומס כראוי + +הגישה ממנפת את החוזקות של Cassandra תוך שמירה על תאימות API מלאה, ומבטיחה שלקוד הקיים יש יתרונות אוטומטיים משיפורי הביצועים. diff --git a/docs/tech-specs/cassandra-performance-refactor.hi.md b/docs/tech-specs/cassandra-performance-refactor.hi.md new file mode 100644 index 00000000..25e9cd3e --- /dev/null +++ b/docs/tech-specs/cassandra-performance-refactor.hi.md @@ -0,0 +1,679 @@ +# तकनीकी विनिर्देश: कैसेंड्रा नॉलेज बेस प्रदर्शन पुनर्निर्माण + +**स्थिति:** मसौदा +**लेखक:** सहायक +**तिथि:** 2025-09-18 + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ कैसेंड्रा नॉलेज बेस कार्यान्वयन में प्रदर्शन संबंधी मुद्दों को संबोधित करता है और आरडीएफ ट्रिपल भंडारण और क्वेरी के लिए अनुकूलन प्रस्तावित करता है। + +## वर्तमान कार्यान्वयन + +### स्कीमा डिज़ाइन + +वर्तमान कार्यान्वयन `trustgraph-flow/trustgraph/direct/cassandra_kg.py` में एक एकल तालिका डिज़ाइन का उपयोग करता है: + +```sql +CREATE TABLE triples ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` + +**माध्यमिक अनुक्रमणिकाएँ:** +`triples_s` ON `s` (विषय) +`triples_p` ON `p` (क्रिया) +`triples_o` ON `o` (वस्तु) + +### क्वेरी पैटर्न + +वर्तमान कार्यान्वयन 8 अलग-अलग क्वेरी पैटर्न का समर्थन करता है: + +1. **get_all(संग्रह, सीमा=50)** - एक संग्रह के लिए सभी त्रिगुट प्राप्त करें + ```sql + SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50 + ``` + +2. **get_s(संग्रह, s, सीमा=10)** - विषय द्वारा खोज। + ```sql + SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10 + ``` + +3. **get_p(संग्रह, p, सीमा=10)** - विधेय द्वारा खोज + ```sql + SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10 + ``` + +4. **get_o(संग्रह, o, सीमा=10)** - ऑब्जेक्ट द्वारा क्वेरी करें। + ```sql + SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10 + ``` + +5. **get_sp(संग्रह, s, p, सीमा=10)** - विषय + विधेय द्वारा खोज। + ```sql + SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10 + ``` + +6. **get_po(collection, p, o, limit=10)** - पूर्व निर्धारित शर्तों और वस्तुओं के आधार पर खोज ⚠️ + ```sql + SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING + ``` + +7. **get_os(संग्रह, o, s, सीमा=10)** - ऑब्जेक्ट + विषय द्वारा क्वेरी ⚠️ + ```sql + SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING + ``` + +8. **get_spo(संग्रह, s, p, o, सीमा=10)** - सटीक त्रिगुट मिलान + ```sql + SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10 + ``` + +### वर्तमान आर्किटेक्चर + +**फ़ाइल: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`** +सभी कार्यों को संभालने वाली एकल `KnowledgeGraph` क्लास +वैश्विक `_active_clusters` सूची के माध्यम से कनेक्शन पूलिंग +निश्चित टेबल नाम: `"triples"` +प्रति उपयोगकर्ता मॉडल के लिए कीस्पेस +फैक्टर 1 के साथ सिंपलस्ट्रैटेजी प्रतिकृति + +**एकीकरण बिंदु:** +**राइट पाथ:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +**क्वेरी पाथ:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` +**नॉलेज स्टोर:** `trustgraph-flow/trustgraph/tables/knowledge.py` + +## पहचाने गए प्रदर्शन संबंधी मुद्दे + +### स्कीमा-स्तरीय मुद्दे + +1. **अकुशल प्राइमरी की डिज़ाइन** + वर्तमान: `PRIMARY KEY (collection, s, p, o)` + सामान्य एक्सेस पैटर्न के लिए खराब क्लस्टरिंग का कारण बनता है + महंगे सेकेंडरी इंडेक्स के उपयोग को मजबूर करता है + +2. **सेकेंडरी इंडेक्स का अत्यधिक उपयोग** ⚠️ + उच्च कार्डिनलिटी कॉलम (s, p, o) पर तीन सेकेंडरी इंडेक्स + कैसेंड्रा में सेकेंडरी इंडेक्स महंगे होते हैं और अच्छी तरह से स्केल नहीं होते हैं + क्वेरी 6 और 7 को `ALLOW FILTERING` की आवश्यकता होती है, जो खराब डेटा मॉडलिंग का संकेत देती है + +3. **हॉट पार्टिशन का जोखिम** + एकल पार्टीशन कुंजी `collection` हॉट पार्टिशन बना सकती है + बड़े संग्रह एकल नोड्स पर केंद्रित होंगे + लोड बैलेंसिंग के लिए कोई वितरण रणनीति नहीं + +### क्वेरी-स्तरीय मुद्दे + +1. **ALLOW FILTERING का उपयोग** ⚠️ + दो क्वेरी प्रकार (get_po, get_os) को `ALLOW FILTERING` की आवश्यकता होती है + ये क्वेरी कई पार्टिशन को स्कैन करती हैं और बेहद महंगी हैं + डेटा के आकार के साथ प्रदर्शन रैखिक रूप से खराब होता है + +2. **अकुशल एक्सेस पैटर्न** + सामान्य आरडीएफ क्वेरी पैटर्न के लिए कोई अनुकूलन नहीं + बार-बार उपयोग किए जाने वाले क्वेरी संयोजनों के लिए कोई कंपाउंड इंडेक्स नहीं + ग्राफ ट्रैवर्सल पैटर्न पर कोई विचार नहीं + +3. **क्वेरी अनुकूलन की कमी** + कोई तैयार स्टेटमेंट कैशिंग नहीं + कोई क्वेरी संकेत या अनुकूलन रणनीतियाँ नहीं + साधारण LIMIT से परे पेजिंग पर कोई विचार नहीं + +## समस्या विवरण + +वर्तमान कैसेंड्रा नॉलेज बेस कार्यान्वयन में दो महत्वपूर्ण प्रदर्शन संबंधी बाधाएं हैं: + +### 1. अकुशल get_po क्वेरी प्रदर्शन + +`get_po(collection, p, o)` क्वेरी `ALLOW FILTERING` की आवश्यकता के कारण बेहद अकुशल है: + +```sql +SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING +``` + +**यह समस्याग्रस्त क्यों है:** +`ALLOW FILTERING` कैसेंड्रा को संग्रह के भीतर सभी विभाजन को स्कैन करने के लिए मजबूर करता है। +डेटा के आकार के साथ प्रदर्शन रैखिक रूप से घटता है। +यह एक सामान्य आरडीएफ क्वेरी पैटर्न है (उन विषयों को खोजना जिनके पास एक विशिष्ट विधेय-वस्तु संबंध है)। +जैसे-जैसे डेटा बढ़ता है, यह क्लस्टर पर महत्वपूर्ण भार डालता है। + +### 2. खराब क्लस्टरिंग रणनीति + +वर्तमान प्राथमिक कुंजी `PRIMARY KEY (collection, s, p, o)` न्यूनतम क्लस्टरिंग लाभ प्रदान करती है: + +**वर्तमान क्लस्टरिंग के साथ समस्याएं:** +विभाजन कुंजी के रूप में `collection` डेटा को प्रभावी ढंग से वितरित नहीं करता है। +अधिकांश संग्रहों में विविध डेटा होता है, जिससे क्लस्टरिंग अप्रभावी हो जाती है। +आरडीएफ प्रश्नों में सामान्य एक्सेस पैटर्न पर कोई विचार नहीं किया गया है। +बड़े संग्रह एकल नोड्स पर "हॉट" विभाजन बनाते हैं। +क्लस्टरिंग कॉलम (s, p, o) विशिष्ट ग्राफ ट्रैवर्सल पैटर्न के लिए अनुकूलित नहीं हैं। + +**प्रभाव:** +क्वेरी डेटा स्थानीयता से लाभान्वित नहीं होती हैं। +खराब कैश उपयोग। +क्लस्टर नोड्स में असमान लोड वितरण। +जैसे-जैसे संग्रह बढ़ते हैं, स्केलेबिलिटी बाधाएं। + +## प्रस्तावित समाधान: 4-टेबल डीनॉर्मलाइज़ेशन रणनीति + +### अवलोकन + +एकल `triples` तालिका को चार उद्देश्य-निर्मित तालिकाओं से बदलें, प्रत्येक विशिष्ट क्वेरी पैटर्न के लिए अनुकूलित है। यह द्वितीयक अनुक्रमणिकाओं और ALLOW FILTERING की आवश्यकता को समाप्त करता है, जबकि सभी प्रकार की क्वेरी के लिए इष्टतम प्रदर्शन प्रदान करता है। चौथी तालिका समग्र विभाजन कुंजियों के बावजूद कुशल संग्रह हटाने को सक्षम बनाती है। + +### नया स्कीमा डिज़ाइन + +**टेबल 1: विषय-केंद्रित क्वेरी (triples_s)** +```sql +CREATE TABLE triples_s ( + collection text, + s text, + p text, + o text, + PRIMARY KEY ((collection, s), p, o) +); +``` +**अनुकूलन:** get_s, get_sp, get_os +**विभाजन कुंजी:** (संग्रह, s) - केवल संग्रह की तुलना में बेहतर वितरण +**समूहीकरण:** (p, o) - विषय के लिए कुशल विधेय/वस्तु लुकअप को सक्षम करता है + +**तालिका 2: विधेय-वस्तु प्रश्न (triples_p)** +```sql +CREATE TABLE triples_p ( + collection text, + p text, + o text, + s text, + PRIMARY KEY ((collection, p), o, s) +); +``` +**अनुकूलन:** get_p, get_po (ALLOW FILTERING को हटाता है!) +**पार्टिशन कुंजी:** (संग्रह, p) - विधेय द्वारा प्रत्यक्ष पहुंच +**क्लस्टरिंग:** (o, s) - कुशल ऑब्जेक्ट-विषय ट्रैवर्सल + +**तालिका 3: ऑब्जेक्ट-केंद्रित प्रश्न (triples_o)** +```sql +CREATE TABLE triples_o ( + collection text, + o text, + s text, + p text, + PRIMARY KEY ((collection, o), s, p) +); +``` +**अनुकूलन:** get_o +**विभाजन कुंजी:** (संग्रह, o) - वस्तु द्वारा प्रत्यक्ष पहुंच +**समूहीकरण:** (s, p) - कुशल विषय-क्रियापद ट्रैवर्सल + +**तालिका 4: संग्रह प्रबंधन और एस.पी.ओ. प्रश्न (triples_collection)** +```sql +CREATE TABLE triples_collection ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` +**अनुकूलन:** get_spo, delete_collection +**विभाजन कुंजी:** केवल संग्रह - कुशल संग्रह-स्तरीय संचालन को सक्षम करता है +**समूहीकरण:** (s, p, o) - मानक त्रिगुट क्रम +**उद्देश्य:** सटीक SPO लुकअप के लिए दोहरे उपयोग और एक हटाने अनुक्रमणिका के रूप में + +### क्वेरी मैपिंग + +| मूल क्वेरी | लक्ष्य तालिका | प्रदर्शन सुधार | +|----------------|-------------|------------------------| +| get_all(संग्रह) | triples_s | ALLOW FILTERING (स्कैन के लिए स्वीकार्य) | +| get_s(संग्रह, s) | triples_s | प्रत्यक्ष विभाजन पहुंच | +| get_p(संग्रह, p) | triples_p | प्रत्यक्ष विभाजन पहुंच | +| get_o(संग्रह, o) | triples_o | प्रत्यक्ष विभाजन पहुंच | +| get_sp(संग्रह, s, p) | triples_s | विभाजन + समूहीकरण | +| get_po(संग्रह, p, o) | triples_p | **अब ALLOW FILTERING नहीं!** | +| get_os(संग्रह, o, s) | triples_o | विभाजन + समूहीकरण | +| get_spo(संग्रह, s, p, o) | triples_collection | सटीक कुंजी लुकअप | +| delete_collection(संग्रह) | triples_collection | अनुक्रमणिका पढ़ें, सभी को बैच में हटाएं | + +### संग्रह हटाने की रणनीति + +संयुक्त विभाजन कुंजियों के साथ, हम सीधे `DELETE FROM table WHERE collection = ?` निष्पादित नहीं कर सकते। इसके बजाय: + +1. **पढ़ने का चरण:** सभी त्रिगुटों को सूचीबद्ध करने के लिए `triples_collection` क्वेरी करें: + ```sql + SELECT s, p, o FROM triples_collection WHERE collection = ? + ``` + यह कुशल है क्योंकि `collection` इस तालिका के लिए विभाजन कुंजी है। + +2. **हटाने का चरण:** प्रत्येक ट्रिपल (s, p, o) के लिए, सभी 4 तालिकाओं से पूर्ण विभाजन कुंजियों का उपयोग करके हटाएं: + ```sql + DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ? + DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ? + DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ? + DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ? + ``` + दक्षता के लिए 100 के समूहों में समूहीकृत किया गया। + +**ट्रेड-ऑफ विश्लेषण:** +✅ वितरित विभाजनों के साथ इष्टतम क्वेरी प्रदर्शन बनाए रखता है। +✅ बड़े संग्रहों के लिए कोई "हॉट" विभाजन नहीं। +❌ अधिक जटिल हटाने का तर्क (पढ़ें-फिर-हटाएं)। +❌ हटाने का समय संग्रह के आकार के समानुपाती होता है। + +### लाभ + +1. **ALLOW FILTERING को समाप्त करता है** - प्रत्येक क्वेरी में एक इष्टतम एक्सेस पथ होता है (सिवाय get_all स्कैन के)। +2. **कोई द्वितीयक इंडेक्स नहीं** - प्रत्येक तालिका अपने क्वेरी पैटर्न के लिए इंडेक्स है। +3. **बेहतर डेटा वितरण** - समग्र विभाजन कुंजियाँ प्रभावी रूप से लोड फैलाती हैं। +4. **अनुमानित प्रदर्शन** - क्वेरी समय परिणाम के आकार के समानुपाती होता है, कुल डेटा के नहीं। +5. **कैसेंड्रा की ताकत का लाभ उठाता है** - कैसेंड्रा के आर्किटेक्चर के लिए डिज़ाइन किया गया। +6. **संग्रह हटाने को सक्षम बनाता है** - triples_collection हटाने के इंडेक्स के रूप में कार्य करता है। + +## कार्यान्वयन योजना + +### उन फ़ाइलों की आवश्यकता है जिनमें परिवर्तन आवश्यक हैं + +#### प्राथमिक कार्यान्वयन फ़ाइल + +**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - पूर्ण पुनर्लेखन आवश्यक है। + +**वर्तमान विधियाँ जिन्हें रिफैक्टर करने की आवश्यकता है:** +```python +# Schema initialization +def init(self) -> None # Replace single table with three tables + +# Insert operations +def insert(self, collection, s, p, o) -> None # Write to all three tables + +# Query operations (API unchanged, implementation optimized) +def get_all(self, collection, limit=50) # Use triples_by_subject +def get_s(self, collection, s, limit=10) # Use triples_by_subject +def get_p(self, collection, p, limit=10) # Use triples_by_po +def get_o(self, collection, o, limit=10) # Use triples_by_object +def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject +def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!) +def get_os(self, collection, o, s, limit=10) # Use triples_by_subject +def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject + +# Collection management +def delete_collection(self, collection) -> None # Delete from all three tables +``` + +#### एकीकरण फ़ाइलें (कोई लॉजिक परिवर्तन आवश्यक नहीं) + +**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`** +कोई बदलाव आवश्यक नहीं - मौजूदा नॉलेज ग्राफ एपीआई का उपयोग करता है +प्रदर्शन में स्वचालित सुधार से लाभ + +**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`** +कोई बदलाव आवश्यक नहीं - मौजूदा नॉलेज ग्राफ एपीआई का उपयोग करता है +प्रदर्शन में स्वचालित सुधार से लाभ + +### अपडेट की आवश्यकता वाली परीक्षण फ़ाइलें + +#### यूनिट टेस्ट +**`tests/unit/test_storage/test_triples_cassandra_storage.py`** +स्कीमा परिवर्तनों के लिए परीक्षण अपेक्षाओं को अपडेट करें +मल्टी-टेबल स्थिरता के लिए परीक्षण जोड़ें +क्वेरी योजनाओं में कोई ALLOW FILTERING न होने की पुष्टि करें + +**`tests/unit/test_query/test_triples_cassandra_query.py`** +प्रदर्शन दावों को अपडेट करें +नए तालिकाओं के खिलाफ सभी 8 क्वेरी पैटर्न का परीक्षण करें +सही तालिकाओं में क्वेरी रूटिंग की पुष्टि करें + +#### एकीकरण परीक्षण +**`tests/integration/test_cassandra_integration.py`** +नए स्कीमा के साथ एंड-टू-एंड परीक्षण +प्रदर्शन बेंचमार्किंग तुलना +तालिकाओं में डेटा स्थिरता सत्यापन + +**`tests/unit/test_storage/test_cassandra_config_integration.py`** +स्कीमा सत्यापन परीक्षणों को अपडेट करें +माइग्रेशन परिदृश्यों का परीक्षण करें + +### कार्यान्वयन रणनीति + +#### चरण 1: स्कीमा और कोर विधियाँ +1. **`init()` विधि को फिर से लिखें** - एक के बजाय चार तालिकाओं का निर्माण करें +2. **`insert()` विधि को फिर से लिखें** - सभी चार तालिकाओं में बैच राइट्स +3. **तैयार कथनों को लागू करें** - इष्टतम प्रदर्शन के लिए +4. **टेबल रूटिंग लॉजिक जोड़ें** - प्रश्नों को इष्टतम तालिकाओं पर निर्देशित करें +5. **संग्रह हटाने को लागू करें** - triples_collection से पढ़ें, सभी तालिकाओं से बैच हटाएं + +#### चरण 2: क्वेरी विधि अनुकूलन +1. **प्रत्येक get_* विधि को फिर से लिखें** ताकि इष्टतम तालिका का उपयोग किया जा सके +2. **सभी ALLOW FILTERING उपयोग को हटा दें** +3. **कुशल क्लस्टरिंग कुंजी उपयोग को लागू करें** +4. **क्वेरी प्रदर्शन लॉगिंग जोड़ें** + +#### चरण 3: संग्रह प्रबंधन +1. **`delete_collection()` को अपडेट करें** - सभी तीन तालिकाओं से हटाएं +2. **संगति सत्यापन जोड़ें** - सुनिश्चित करें कि सभी तालिकाओं को सिंक में रखा जाए +3. **बैच ऑपरेशंस लागू करें** - परमाणु मल्टी-टेबल ऑपरेशंस के लिए + +### प्रमुख कार्यान्वयन विवरण + +#### बैच राइट रणनीति +```python +def insert(self, collection, s, p, o): + batch = BatchStatement() + + # Insert into all four tables + batch.add(self.insert_subject_stmt, (collection, s, p, o)) + batch.add(self.insert_po_stmt, (collection, p, o, s)) + batch.add(self.insert_object_stmt, (collection, o, s, p)) + batch.add(self.insert_collection_stmt, (collection, s, p, o)) + + self.session.execute(batch) +``` + +#### प्रश्न रूटिंग लॉजिक (Query Routing Logic) +```python +def get_po(self, collection, p, o, limit=10): + # Route to triples_p table - NO ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) + +def get_spo(self, collection, s, p, o, limit=10): + # Route to triples_collection table for exact SPO lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) +``` + +#### संग्रह हटाने का तर्क +```python +def delete_collection(self, collection): + # Step 1: Read all triples from collection table + rows = self.session.execute( + f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s", + (collection,) + ) + + # Step 2: Batch delete from all 4 tables + batch = BatchStatement() + count = 0 + + for row in rows: + s, p, o = row.s, row.p, row.o + + # Delete using full partition keys for each table + batch.add(SimpleStatement( + f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?" + ), (collection, p, o, s)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?" + ), (collection, o, s, p)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + count += 1 + + # Execute every 100 triples to avoid oversized batches + if count % 100 == 0: + self.session.execute(batch) + batch = BatchStatement() + + # Execute remaining deletions + if count % 100 != 0: + self.session.execute(batch) + + logger.info(f"Deleted {count} triples from collection {collection}") +``` + +#### तैयार स्टेटमेंट अनुकूलन (तैयार कथन अनुकूलन) +```python +def prepare_statements(self): + # Cache prepared statements for better performance + self.insert_subject_stmt = self.session.prepare( + f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + self.insert_po_stmt = self.session.prepare( + f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)" + ) + self.insert_object_stmt = self.session.prepare( + f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)" + ) + self.insert_collection_stmt = self.session.prepare( + f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + # ... query statements +``` + +## माइग्रेशन रणनीति + +### डेटा माइग्रेशन दृष्टिकोण + +#### विकल्प 1: ब्लू-ग्रीन परिनियोजन (अनुशंसित) +1. **नए स्कीमा को मौजूदा स्कीमा के साथ तैनात करें** - अस्थायी रूप से अलग-अलग टेबल नामों का उपयोग करें +2. **डबल-राइट अवधि** - संक्रमण के दौरान पुराने और नए दोनों स्कीमा में लिखें +3. **बैकग्राउंड माइग्रेशन** - मौजूदा डेटा को नई तालिकाओं में कॉपी करें +4. **रीड स्विच करें** - डेटा माइग्रेट होने के बाद प्रश्नों को नई तालिकाओं पर रूट करें +5. **पुराने तालिकाओं को हटाएं** - सत्यापन अवधि के बाद + +#### विकल्प 2: इन-प्लेस माइग्रेशन +1. **स्कीमा जोड़ना** - मौजूदा कीस्पेस में नई तालिकाएँ बनाएँ +2. **डेटा माइग्रेशन स्क्रिप्ट** - बैच कॉपी पुराने टेबल से नई तालिकाओं में +3. **एप्लिकेशन अपडेट** - माइग्रेशन पूरा होने के बाद नया कोड तैनात करें +4. **पुरानी टेबल की सफाई** - पुरानी टेबल और इंडेक्स हटाएं + +### पश्चगामी अनुकूलता + +#### परिनियोजन रणनीति +```python +# Environment variable to control table usage during migration +USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' + +class KnowledgeGraph: + def __init__(self, ...): + if USE_LEGACY_TABLES: + self.init_legacy_schema() + else: + self.init_optimized_schema() +``` + +#### माइग्रेशन स्क्रिप्ट +```python +def migrate_data(): + # Read from old table + old_triples = session.execute("SELECT collection, s, p, o FROM triples") + + # Batch write to new tables + for batch in batched(old_triples, 100): + batch_stmt = BatchStatement() + for row in batch: + # Add to all three new tables + batch_stmt.add(insert_subject_stmt, row) + batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s)) + batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p)) + session.execute(batch_stmt) +``` + +### सत्यापन रणनीति + +#### डेटा संगति जांच +```python +def validate_migration(): + # Count total records in old vs new tables + old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,)) + new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,)) + + assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}" + + # Spot check random samples + sample_queries = generate_test_queries() + for query in sample_queries: + old_result = execute_legacy_query(query) + new_result = execute_optimized_query(query) + assert old_result == new_result, f"Query results differ for {query}" +``` + +## परीक्षण रणनीति + +### प्रदर्शन परीक्षण + +#### बेंचमार्क परिदृश्य +1. **क्वेरी प्रदर्शन तुलना** + सभी 8 क्वेरी प्रकारों के लिए पूर्व/पश्च प्रदर्शन मेट्रिक्स + `get_po` प्रदर्शन सुधार पर ध्यान केंद्रित करें (ALLOW FILTERING को हटाना) + विभिन्न डेटा आकारों के तहत क्वेरी विलंबता को मापें + +2. **लोड परीक्षण** + समवर्ती क्वेरी निष्पादन + बैच ऑपरेशनों के साथ लेखन थ्रूपुट + मेमोरी और सीपीयू उपयोग + +3. **स्केलेबिलिटी परीक्षण** + बढ़ते संग्रह आकारों के साथ प्रदर्शन + मल्टी-कलेक्शन क्वेरी वितरण + क्लस्टर नोड उपयोग + +#### परीक्षण डेटा सेट +**छोटा:** प्रति संग्रह 10K त्रिगुण +**मध्यम:** प्रति संग्रह 100K त्रिगुण +**बड़ा:** 1M+ त्रिगुण +**एकाधिक संग्रह:** परीक्षण विभाजन वितरण + +### कार्यात्मक परीक्षण + +#### यूनिट टेस्ट अपडेट +```python +# Example test structure for new implementation +class TestCassandraKGPerformance: + def test_get_po_no_allow_filtering(self): + # Verify get_po queries don't use ALLOW FILTERING + with patch('cassandra.cluster.Session.execute') as mock_execute: + kg.get_po('test_collection', 'predicate', 'object') + executed_query = mock_execute.call_args[0][0] + assert 'ALLOW FILTERING' not in executed_query + + def test_multi_table_consistency(self): + # Verify all tables stay in sync + kg.insert('test', 's1', 'p1', 'o1') + + # Check all tables contain the triple + assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1') + assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1') + assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1') +``` + +#### एकीकरण परीक्षण अपडेट +```python +class TestCassandraIntegration: + def test_query_performance_regression(self): + # Ensure new implementation is faster than old + old_time = benchmark_legacy_get_po() + new_time = benchmark_optimized_get_po() + assert new_time < old_time * 0.5 # At least 50% improvement + + def test_end_to_end_workflow(self): + # Test complete write -> query -> delete cycle + # Verify no performance degradation in integration +``` + +### रोलबैक योजना + +#### त्वरित रोलबैक रणनीति +1. **पर्यावरण चर स्विच** - तुरंत पुराने तालिकाओं पर वापस स्विच करें +2. **पुराने तालिकाओं को बनाए रखें** - प्रदर्शन साबित होने तक उन्हें हटाएं नहीं +3. **निगरानी अलर्ट** - त्रुटि दर/विलंबता के आधार पर स्वचालित रोलबैक ट्रिगर + +#### रोलबैक सत्यापन +```python +def rollback_to_legacy(): + # Set environment variable + os.environ['CASSANDRA_USE_LEGACY'] = 'true' + + # Restart services to pick up change + restart_cassandra_services() + + # Validate functionality + run_smoke_tests() +``` + +## जोखिम और विचार + +### प्रदर्शन जोखिम +**लेखन विलंबता में वृद्धि** - प्रति सम्मिलित 4x लेखन संचालन (3-तालिका दृष्टिकोण से 33% अधिक) +**भंडारण ओवरहेड** - 4x भंडारण आवश्यकता (3-तालिका दृष्टिकोण से 33% अधिक) +**बैच लेखन विफलताएं** - उचित त्रुटि प्रबंधन की आवश्यकता +**हटाने की जटिलता** - संग्रह हटाने के लिए रीड-देन-डिलीट लूप की आवश्यकता होती है + +### परिचालन जोखिम +**स्थानांतरण जटिलता** - बड़े डेटासेट के लिए डेटा स्थानांतरण +**संगति चुनौतियां** - यह सुनिश्चित करना कि सभी तालिकाएं सिंक्रनाइज़ रहें +**निगरानी अंतराल** - मल्टी-टेबल ऑपरेशनों के लिए नए मेट्रिक्स की आवश्यकता + +### शमन रणनीतियाँ +1. **धीरे-धीरे रोलआउट** - छोटे संग्रहों से शुरुआत करें +2. **व्यापक निगरानी** - सभी प्रदर्शन मेट्रिक्स को ट्रैक करें +3. **स्वचालित सत्यापन** - निरंतर संगति जांच +4. **त्वरित रोलबैक क्षमता** - पर्यावरण-आधारित तालिका चयन + +## सफलता मानदंड + +### प्रदर्शन सुधार +[ ] **ALLOW FILTERING को समाप्त करें** - get_po और get_os क्वेरी फ़िल्टरिंग के बिना चलती हैं +[ ] **क्वेरी विलंबता में कमी** - क्वेरी प्रतिक्रिया समय में 50%+ सुधार +[ ] **बेहतर लोड वितरण** - कोई हॉट विभाजन नहीं, क्लस्टर नोड्स में समान लोड +[ ] **स्केलेबल प्रदर्शन** - क्वेरी समय परिणाम आकार के समानुपाती, कुल डेटा के समानुपाती नहीं + +### कार्यात्मक आवश्यकताएँ +[ ] **एपीआई संगतता** - सभी मौजूदा कोड अपरिवर्तित रूप से काम करना जारी रखता है +[ ] **डेटा संगति** - तीनों तालिकाओं को सिंक्रनाइज़ रखा जाता है +[ ] **कोई डेटा हानि नहीं** - माइग्रेशन सभी मौजूदा त्रिगुणों को संरक्षित करता है +[ ] **पिछड़ा संगतता** - विरासत स्कीमा पर वापस रोलबैक करने की क्षमता + +### परिचालन आवश्यकताएँ +[ ] **सुरक्षित स्थानांतरण** - रोलबैक क्षमता के साथ ब्लू-ग्रीन परिनियोजन +[ ] **निगरानी कवरेज** - मल्टी-टेबल ऑपरेशनों के लिए व्यापक मेट्रिक्स +[ ] **परीक्षण कवरेज** - सभी क्वेरी पैटर्न प्रदर्शन बेंचमार्क के साथ परीक्षण किए गए +[ ] **प्रलेखन** - अद्यतन परिनियोजन और परिचालन प्रक्रियाएं + +## समयरेखा + +### चरण 1: कार्यान्वयन +[ ] मल्टी-टेबल स्कीमा के साथ `cassandra_kg.py` को फिर से लिखें +[ ] बैच लेखन संचालन लागू करें +[ ] तैयार स्टेटमेंट अनुकूलन जोड़ें +[ ] यूनिट परीक्षण अपडेट करें + +### चरण 2: एकीकरण परीक्षण +[ ] एकीकरण परीक्षण अपडेट करें +[ ] प्रदर्शन बेंचमार्किंग +[ ] यथार्थवादी डेटा वॉल्यूम के साथ लोड परीक्षण +[ ] डेटा संगति के लिए सत्यापन स्क्रिप्ट + +### चरण 3: माइग्रेशन योजना +[ ] ब्लू-ग्रीन परिनियोजन स्क्रिप्ट +[ ] डेटा माइग्रेशन उपकरण +[ ] निगरानी डैशबोर्ड अपडेट +[ ] रोलबैक प्रक्रियाएं + +### चरण 4: उत्पादन परिनियोजन +[ ] उत्पादन में क्रमिक रोलआउट +[ ] प्रदर्शन निगरानी और सत्यापन +[ ] विरासत तालिका सफाई +[ ] प्रलेखन अपडेट + +## निष्कर्ष + +यह मल्टी-टेबल डीनॉर्मलाइज़ेशन रणनीति दो महत्वपूर्ण प्रदर्शन बाधाओं को सीधे संबोधित करती है: + +1. **महंगे ALLOW FILTERING को समाप्त करता है** प्रत्येक क्वेरी पैटर्न के लिए इष्टतम तालिका संरचनाएं प्रदान करके +2. **बेहतर क्लस्टरिंग प्रभावशीलता** समग्र विभाजन कुंजियों के माध्यम से जो लोड को ठीक से वितरित करते हैं + +यह दृष्टिकोण कैसेंड्रा की ताकत का लाभ उठाता है जबकि पूर्ण एपीआई संगतता बनाए रखता है, यह सुनिश्चित करता है कि मौजूदा कोड प्रदर्शन सुधारों से स्वचालित रूप से लाभान्वित होता है। diff --git a/docs/tech-specs/cassandra-performance-refactor.pt.md b/docs/tech-specs/cassandra-performance-refactor.pt.md new file mode 100644 index 00000000..dc4740a7 --- /dev/null +++ b/docs/tech-specs/cassandra-performance-refactor.pt.md @@ -0,0 +1,679 @@ +# Especificação Técnica: Refatoração de Desempenho da Base de Conhecimento Cassandra + +**Status:** Rascunho +**Autor:** Assistente +**Data:** 2025-09-18 + +## Visão Geral + +Esta especificação aborda problemas de desempenho na implementação da base de conhecimento Cassandra TrustGraph e propõe otimizações para o armazenamento e consulta de triplas RDF. + +## Implementação Atual + +### Design do Esquema + +A implementação atual utiliza um design de tabela única em `trustgraph-flow/trustgraph/direct/cassandra_kg.py`: + +```sql +CREATE TABLE triples ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` + +**Índices Secundários:** +`triples_s` EM `s` (sujeito) +`triples_p` EM `p` (predicado) +`triples_o` EM `o` (objeto) + +### Padrões de Consulta + +A implementação atual suporta 8 padrões de consulta distintos: + +1. **get_all(coleção, limite=50)** - Recupera todas as triplas para uma coleção + ```sql + SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50 + ``` + +2. **get_s(collection, s, limit=10)** - Consulta por assunto + ```sql + SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10 + ``` + +3. **get_p(collection, p, limit=10)** - Consulta por predicado + ```sql + SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10 + ``` + +4. **get_o(collection, o, limit=10)** - Consulta por objeto + ```sql + SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10 + ``` + +5. **get_sp(collection, s, p, limit=10)** - Consulta por sujeito + predicado + ```sql + SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10 + ``` + +6. **get_po(collection, p, o, limit=10)** - Consulta por predicado + objeto ⚠️ + ```sql + SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING + ``` + +7. **get_os(collection, o, s, limit=10)** - Consulta por objeto + sujeito ⚠️ + ```sql + SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING + ``` + +8. **get_spo(collection, s, p, o, limit=10)** - Correspondência exata de tripla. + ```sql + SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10 + ``` + +### Arquitetura Atual + +**Arquivo: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`** +Classe única `KnowledgeGraph` que gerencia todas as operações +Pool de conexões através de uma lista global `_active_clusters` +Nome de tabela fixo: `"triples"` +Modelo de keyspace por usuário +Replicação SimpleStrategy com fator 1 + +**Pontos de Integração:** +**Caminho de Escrita:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +**Caminho de Consulta:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` +**Armazenamento de Conhecimento:** `trustgraph-flow/trustgraph/tables/knowledge.py` + +## Problemas de Desempenho Identificados + +### Problemas no Nível do Schema + +1. **Design de Chave Primária Ineficiente** + Atual: `PRIMARY KEY (collection, s, p, o)` + Resulta em agrupamento inadequado para padrões de acesso comuns + Força o uso de índices secundários caros + +2. **Uso Excessivo de Índices Secundários** ⚠️ + Três índices secundários em colunas de alta cardinalidade (s, p, o) + Índices secundários em Cassandra são caros e não escalam bem + As consultas 6 e 7 requerem `ALLOW FILTERING`, indicando modelagem de dados inadequada + +3. **Risco de Partições Quentes** + Uma única chave de partição `collection` pode criar partições quentes + Grandes coleções se concentrarão em nós únicos + Não há estratégia de distribuição para balanceamento de carga + +### Problemas no Nível da Consulta + +1. **Uso de ALLOW FILTERING** ⚠️ + Dois tipos de consulta (get_po, get_os) requerem `ALLOW FILTERING` + Essas consultas escaneiam várias partições e são extremamente caras + O desempenho degrada linearmente com o tamanho dos dados + +2. **Padrões de Acesso Ineficientes** + Não há otimização para padrões de consulta RDF comuns + Índices compostos ausentes para combinações de consulta frequentes + Não há consideração para padrões de travessia de grafos + +3. **Falta de Otimização de Consulta** + Não há cache de prepared statements + Não há dicas de consulta ou estratégias de otimização + Não há consideração para paginação além de um simples LIMIT + +## Declaração do Problema + +A implementação atual da base de conhecimento Cassandra tem dois gargalos críticos de desempenho: + +### 1. Desempenho Ineficiente da Consulta get_po + +A consulta `get_po(collection, p, o)` é extremamente ineficiente devido à necessidade de `ALLOW FILTERING`: + +```sql +SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING +``` + +**Por que isso é problemático:** +`ALLOW FILTERING` força o Cassandra a escanear todas as partições dentro da coleção. +O desempenho diminui linearmente com o tamanho dos dados. +Este é um padrão de consulta RDF comum (encontrar sujeitos que têm um relacionamento específico de predicado-objeto). +Cria uma carga significativa no cluster à medida que os dados crescem. + +### 2. Estratégia de Clustering Inadequada + +A chave primária atual `PRIMARY KEY (collection, s, p, o)` oferece benefícios mínimos de clustering: + +**Problemas com o clustering atual:** +`collection` como chave de partição não distribui os dados de forma eficaz. +A maioria das coleções contém dados diversos, tornando o clustering ineficaz. +Não há consideração para padrões de acesso comuns em consultas RDF. +Coleções grandes criam partições quentes em nós únicos. +As colunas de clustering (s, p, o) não otimizam para padrões típicos de travessia de grafos. + +**Impacto:** +As consultas não se beneficiam da localidade dos dados. +Utilização inadequada do cache. +Distribuição desigual de carga entre os nós do cluster. +Gargalos de escalabilidade à medida que as coleções crescem. + +## Solução Proposta: Estratégia de Desnormalização de 4 Tabelas + +### Visão Geral + +Substitua a única tabela `triples` por quatro tabelas projetadas especificamente, cada uma otimizada para padrões de consulta específicos. Isso elimina a necessidade de índices secundários e ALLOW FILTERING, ao mesmo tempo em que fornece desempenho ideal para todos os tipos de consulta. A quarta tabela permite a exclusão eficiente de coleções, apesar das chaves de partição compostas. + +### Novo Design de Esquema + +**Tabela 1: Consultas Centradas no Sujeito (triples_s)** +```sql +CREATE TABLE triples_s ( + collection text, + s text, + p text, + o text, + PRIMARY KEY ((collection, s), p, o) +); +``` +**Otimiza:** get_s, get_sp, get_os +**Chave de Partição:** (coleção, s) - Melhor distribuição do que apenas a coleção +**Agrupamento:** (p, o) - Permite pesquisas eficientes de predicados/objetos para um sujeito + +**Tabela 2: Consultas Predicado-Objeto (triples_p)** +```sql +CREATE TABLE triples_p ( + collection text, + p text, + o text, + s text, + PRIMARY KEY ((collection, p), o, s) +); +``` +**Otimiza:** get_p, get_po (elimina ALLOW FILTERING!) +**Chave de Partição:** (coleção, p) - Acesso direto por predicado +**Agrupamento:** (o, s) - Traversal eficiente de objeto-sujeito + +**Tabela 3: Consultas Orientadas a Objetos (triples_o)** +```sql +CREATE TABLE triples_o ( + collection text, + o text, + s text, + p text, + PRIMARY KEY ((collection, o), s, p) +); +``` +**Otimiza:** get_o +**Chave de Partição:** (coleção, o) - Acesso direto por objeto +**Agrupamento:** (s, p) - Traversal eficiente de sujeito-predicado + +**Tabela 4: Gerenciamento de Coleções e Consultas SPO (triples_collection)** +```sql +CREATE TABLE triples_collection ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` +**Otimiza:** get_spo, delete_collection +**Chave de Partição:** coleção apenas - Permite operações eficientes no nível da coleção. +**Agrupamento:** (s, p, o) - Ordenação padrão de triplas. +**Propósito:** Uso duplo para pesquisas exatas de SPO e como índice de exclusão. + +### Mapeamento de Consultas + +| Consulta Original | Tabela de Destino | Melhoria de Desempenho | +|----------------|-------------|------------------------| +| get_all(collection) | triples_s | PERMITE FILTRAGEM (aceitável para varredura) | +| get_s(collection, s) | triples_s | Acesso direto à partição | +| get_p(collection, p) | triples_p | Acesso direto à partição | +| get_o(collection, o) | triples_o | Acesso direto à partição | +| get_sp(collection, s, p) | triples_s | Partição + agrupamento | +| get_po(collection, p, o) | triples_p | **Não mais PERMITE FILTRAGEM!** | +| get_os(collection, o, s) | triples_o | Partição + agrupamento | +| get_spo(collection, s, p, o) | triples_collection | Pesquisa de chave exata | +| delete_collection(collection) | triples_collection | Lê o índice, exclusão em lote de todos | + +### Estratégia de Exclusão de Coleção + +Com chaves de partição compostas, não podemos simplesmente executar `DELETE FROM table WHERE collection = ?`. Em vez disso: + +1. **Fase de Leitura:** Consulta `triples_collection` para enumerar todas as triplas: + ```sql + SELECT s, p, o FROM triples_collection WHERE collection = ? + ``` + Isso é eficiente, já que `collection` é a chave de partição para esta tabela. + +2. **Fase de Exclusão:** Para cada tripla (s, p, o), exclua de todas as 4 tabelas usando as chaves de partição completas: + ```sql + DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ? + DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ? + DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ? + DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ? + ``` + Agrupado em lotes de 100 para maior eficiência. + +**Análise de Compromissos:** +✅ Mantém o desempenho ideal das consultas com partições distribuídas. +✅ Sem partições com alta carga para grandes coleções. +❌ Lógica de exclusão mais complexa (leitura e depois exclusão). +❌ Tempo de exclusão proporcional ao tamanho da coleção. + +### Benefícios + +1. **Elimina ALLOW FILTERING** - Cada consulta tem um caminho de acesso ideal (exceto a varredura get_all). +2. **Sem Índices Secundários** - Cada tabela É o índice para seu padrão de consulta. +3. **Melhor Distribuição de Dados** - As chaves de partição compostas distribuem a carga de forma eficaz. +4. **Desempenho Previsível** - O tempo de consulta é proporcional ao tamanho do resultado, não ao tamanho total dos dados. +5. **Aproveita os Pontos Fortes do Cassandra** - Projetado para a arquitetura do Cassandra. +6. **Permite a Exclusão de Coleções** - triples_collection serve como índice de exclusão. + +## Plano de Implementação + +### Arquivos que Requerem Alterações + +#### Arquivo de Implementação Primário + +**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - Reescrita completa necessária. + +**Métodos Atuais a Serem Refatorados:** +```python +# Schema initialization +def init(self) -> None # Replace single table with three tables + +# Insert operations +def insert(self, collection, s, p, o) -> None # Write to all three tables + +# Query operations (API unchanged, implementation optimized) +def get_all(self, collection, limit=50) # Use triples_by_subject +def get_s(self, collection, s, limit=10) # Use triples_by_subject +def get_p(self, collection, p, limit=10) # Use triples_by_po +def get_o(self, collection, o, limit=10) # Use triples_by_object +def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject +def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!) +def get_os(self, collection, o, s, limit=10) # Use triples_by_subject +def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject + +# Collection management +def delete_collection(self, collection) -> None # Delete from all three tables +``` + +#### Arquivos de Integração (Nenhuma Alteração de Lógica Necessária) + +**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`** +Nenhuma alteração necessária - utiliza a API KnowledgeGraph existente +Beneficia automaticamente das melhorias de desempenho + +**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`** +Nenhuma alteração necessária - utiliza a API KnowledgeGraph existente +Beneficia automaticamente das melhorias de desempenho + +### Arquivos de Teste que Requerem Atualizações + +#### Testes Unitários +**`tests/unit/test_storage/test_triples_cassandra_storage.py`** +Atualizar as expectativas dos testes para as alterações no esquema +Adicionar testes para a consistência de várias tabelas +Verificar se não há ALLOW FILTERING nos planos de consulta + +**`tests/unit/test_query/test_triples_cassandra_query.py`** +Atualizar as asserções de desempenho +Testar todos os 8 padrões de consulta contra as novas tabelas +Verificar o roteamento da consulta para as tabelas corretas + +#### Testes de Integração +**`tests/integration/test_cassandra_integration.py`** +Testes de ponta a ponta com o novo esquema +Comparativos de benchmarking de desempenho +Verificação da consistência dos dados entre as tabelas + +**`tests/unit/test_storage/test_cassandra_config_integration.py`** +Atualizar os testes de validação de esquema +Testar cenários de migração + +### Estratégia de Implementação + +#### Fase 1: Esquema e Métodos Principais +1. **Reescrever o método `init()`** - Criar quatro tabelas em vez de uma +2. **Reescrever o método `insert()`** - Gravações em lote em todas as quatro tabelas +3. **Implementar instruções preparadas** - Para desempenho ideal +4. **Adicionar lógica de roteamento de tabela** - Direcionar consultas para as tabelas mais adequadas +5. **Implementar a exclusão de coleções** - Ler de triples_collection, excluir em lote de todas as tabelas + +#### Fase 2: Otimização do Método de Consulta +1. **Reescrever cada método get_*** para usar a tabela mais adequada +2. **Remover todo o uso de ALLOW FILTERING** +3. **Implementar o uso eficiente da chave de agrupamento** +4. **Adicionar registro de desempenho da consulta** + +#### Fase 3: Gerenciamento de Coleções +1. **Atualizar `delete_collection()`** - Remover de todas as três tabelas +2. **Adicionar verificação de consistência** - Garantir que todas as tabelas permaneçam sincronizadas +3. **Implementar operações em lote** - Para operações multi-tabela atômicas + +### Detalhes Chave da Implementação + +#### Estratégia de Gravação em Lote +```python +def insert(self, collection, s, p, o): + batch = BatchStatement() + + # Insert into all four tables + batch.add(self.insert_subject_stmt, (collection, s, p, o)) + batch.add(self.insert_po_stmt, (collection, p, o, s)) + batch.add(self.insert_object_stmt, (collection, o, s, p)) + batch.add(self.insert_collection_stmt, (collection, s, p, o)) + + self.session.execute(batch) +``` + +#### Lógica de Roteamento de Consultas +```python +def get_po(self, collection, p, o, limit=10): + # Route to triples_p table - NO ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) + +def get_spo(self, collection, s, p, o, limit=10): + # Route to triples_collection table for exact SPO lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) +``` + +#### Lógica de Exclusão de Coleções +```python +def delete_collection(self, collection): + # Step 1: Read all triples from collection table + rows = self.session.execute( + f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s", + (collection,) + ) + + # Step 2: Batch delete from all 4 tables + batch = BatchStatement() + count = 0 + + for row in rows: + s, p, o = row.s, row.p, row.o + + # Delete using full partition keys for each table + batch.add(SimpleStatement( + f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?" + ), (collection, p, o, s)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?" + ), (collection, o, s, p)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + count += 1 + + # Execute every 100 triples to avoid oversized batches + if count % 100 == 0: + self.session.execute(batch) + batch = BatchStatement() + + # Execute remaining deletions + if count % 100 != 0: + self.session.execute(batch) + + logger.info(f"Deleted {count} triples from collection {collection}") +``` + +#### Otimização de Instruções Preparadas +```python +def prepare_statements(self): + # Cache prepared statements for better performance + self.insert_subject_stmt = self.session.prepare( + f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + self.insert_po_stmt = self.session.prepare( + f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)" + ) + self.insert_object_stmt = self.session.prepare( + f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)" + ) + self.insert_collection_stmt = self.session.prepare( + f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + # ... query statements +``` + +## Estratégia de Migração + +### Abordagem de Migração de Dados + +#### Opção 1: Implantação Blue-Green (Recomendada) +1. **Implantar o novo esquema junto com o existente** - Use nomes de tabelas diferentes temporariamente +2. **Período de escrita dupla** - Escrever tanto no esquema antigo quanto no novo durante a transição +3. **Migração em segundo plano** - Copiar dados existentes para novas tabelas +4. **Alternar leituras** - Direcionar consultas para novas tabelas assim que os dados forem migrados +5. **Remover tabelas antigas** - Após o período de verificação + +#### Opção 2: Migração no Local +1. **Adição de esquema** - Criar novas tabelas no keyspace existente +2. **Script de migração de dados** - Copiar em lote da tabela antiga para as novas tabelas +3. **Atualização do aplicativo** - Implantar novo código após a conclusão da migração +4. **Limpeza da tabela antiga** - Remover a tabela antiga e os índices + +### Compatibilidade com Versões Anteriores + +#### Estratégia de Implantação +```python +# Environment variable to control table usage during migration +USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' + +class KnowledgeGraph: + def __init__(self, ...): + if USE_LEGACY_TABLES: + self.init_legacy_schema() + else: + self.init_optimized_schema() +``` + +#### Script de Migração +```python +def migrate_data(): + # Read from old table + old_triples = session.execute("SELECT collection, s, p, o FROM triples") + + # Batch write to new tables + for batch in batched(old_triples, 100): + batch_stmt = BatchStatement() + for row in batch: + # Add to all three new tables + batch_stmt.add(insert_subject_stmt, row) + batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s)) + batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p)) + session.execute(batch_stmt) +``` + +### Estratégia de Validação + +#### Verificações de Consistência de Dados +```python +def validate_migration(): + # Count total records in old vs new tables + old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,)) + new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,)) + + assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}" + + # Spot check random samples + sample_queries = generate_test_queries() + for query in sample_queries: + old_result = execute_legacy_query(query) + new_result = execute_optimized_query(query) + assert old_result == new_result, f"Query results differ for {query}" +``` + +## Estratégia de Testes + +### Testes de Desempenho + +#### Cenários de Benchmark +1. **Comparação de Desempenho de Consultas** + Métricas de desempenho antes/depois para todos os 8 tipos de consulta + Foco na melhoria de desempenho de `get_po` (eliminar `ALLOW FILTERING`) + Medir a latência da consulta sob vários tamanhos de dados + +2. **Testes de Carga** + Execução de consultas concorrentes + Taxa de transferência de escrita com operações em lote + Utilização de memória e CPU + +3. **Testes de Escalabilidade** + Desempenho com tamanhos de coleção crescentes + Distribuição de consultas em várias coleções + Utilização de nós do cluster + +#### Conjuntos de Dados de Teste +**Pequeno:** 10K triplas por coleção +**Médio:** 100K triplas por coleção +**Grande:** 1M+ triplas por coleção +**Múltiplas coleções:** Testar a distribuição de partições + +### Testes Funcionais + +#### Atualizações de Testes Unitários +```python +# Example test structure for new implementation +class TestCassandraKGPerformance: + def test_get_po_no_allow_filtering(self): + # Verify get_po queries don't use ALLOW FILTERING + with patch('cassandra.cluster.Session.execute') as mock_execute: + kg.get_po('test_collection', 'predicate', 'object') + executed_query = mock_execute.call_args[0][0] + assert 'ALLOW FILTERING' not in executed_query + + def test_multi_table_consistency(self): + # Verify all tables stay in sync + kg.insert('test', 's1', 'p1', 'o1') + + # Check all tables contain the triple + assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1') + assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1') + assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1') +``` + +#### Atualizações do Teste de Integração +```python +class TestCassandraIntegration: + def test_query_performance_regression(self): + # Ensure new implementation is faster than old + old_time = benchmark_legacy_get_po() + new_time = benchmark_optimized_get_po() + assert new_time < old_time * 0.5 # At least 50% improvement + + def test_end_to_end_workflow(self): + # Test complete write -> query -> delete cycle + # Verify no performance degradation in integration +``` + +### Plano de Reversão + +#### Estratégia de Reversão Rápida +1. **Alternância de variáveis de ambiente** - Retorne imediatamente para as tabelas legadas. +2. **Mantenha as tabelas legadas** - Não as exclua até que o desempenho seja comprovado. +3. **Alertas de monitoramento** - Disparos de reversão automatizados com base em taxas de erro/latência. + +#### Validação da Reversão +```python +def rollback_to_legacy(): + # Set environment variable + os.environ['CASSANDRA_USE_LEGACY'] = 'true' + + # Restart services to pick up change + restart_cassandra_services() + + # Validate functionality + run_smoke_tests() +``` + +## Riscos e Considerações + +### Riscos de Desempenho +**Aumento da latência de escrita** - 4 operações de escrita por inserção (33% a mais do que a abordagem de 3 tabelas) +**Sobrecarga de armazenamento** - 4x o requisito de armazenamento (33% a mais do que a abordagem de 3 tabelas) +**Falhas de escrita em lote** - Necessidade de tratamento adequado de erros +**Complexidade da exclusão** - A exclusão da coleção requer um loop de leitura e exclusão + +### Riscos Operacionais +**Complexidade da migração** - Migração de dados para grandes conjuntos de dados +**Desafios de consistência** - Garantir que todas as tabelas permaneçam sincronizadas +**Lacunas de monitoramento** - Necessidade de novas métricas para operações de várias tabelas + +### Estratégias de Mitigação +1. **Implantação gradual** - Começar com pequenas coleções +2. **Monitoramento abrangente** - Rastrear todas as métricas de desempenho +3. **Validação automatizada** - Verificação contínua de consistência +4. **Capacidade de reversão rápida** - Seleção de tabela baseada no ambiente + +## Critérios de Sucesso + +### Melhorias de Desempenho +[ ] **Eliminar ALLOW FILTERING** - as consultas get_po e get_os são executadas sem filtragem +[ ] **Redução da latência da consulta** - melhoria de 50% ou mais nos tempos de resposta da consulta +[ ] **Melhor distribuição de carga** - Sem partições quentes, distribuição uniforme entre os nós do cluster +[ ] **Desempenho escalável** - Tempo de consulta proporcional ao tamanho do resultado, não ao volume total de dados + +### Requisitos Funcionais +[ ] **Compatibilidade da API** - Todo o código existente continua a funcionar sem alterações +[ ] **Consistência de dados** - As três tabelas permanecem sincronizadas +[ ] **Nenhuma perda de dados** - A migração preserva todas as triplas existentes +[ ] **Compatibilidade com versões anteriores** - Capacidade de reverter para o esquema legado + +### Requisitos Operacionais +[ ] **Migração segura** - Implantação blue-green com capacidade de reversão +[ ] **Cobertura de monitoramento** - Métricas abrangentes para operações de várias tabelas +[ ] **Cobertura de teste** - Todos os padrões de consulta testados com benchmarks de desempenho +[ ] **Documentação** - Procedimentos de implantação e operação atualizados + +## Cronograma + +### Fase 1: Implementação +[ ] Reescrever `cassandra_kg.py` com o esquema de várias tabelas +[ ] Implementar operações de escrita em lote +[ ] Adicionar otimização de declaração preparada +[ ] Atualizar testes unitários + +### Fase 2: Testes de Integração +[ ] Atualizar testes de integração +[ ] Benchmarking de desempenho +[ ] Teste de carga com volumes de dados realistas +[ ] Scripts de validação para consistência de dados + +### Fase 3: Planejamento da Migração +[ ] Scripts de implantação blue-green +[ ] Ferramentas de migração de dados +[ ] Atualizações do painel de monitoramento +[ ] Procedimentos de reversão + +### Fase 4: Implantação em Produção +[ ] Implantação gradual em produção +[ ] Monitoramento e validação de desempenho +[ ] Limpeza de tabelas legadas +[ ] Atualizações de documentação + +## Conclusão + +Esta estratégia de desnormalização multi-tabela aborda diretamente os dois gargalos de desempenho críticos: + +1. **Elimina o ALLOW FILTERING caro** fornecendo estruturas de tabela ideais para cada padrão de consulta +2. **Melhora a eficácia do agrupamento** por meio de chaves de partição compostas que distribuem a carga adequadamente + +A abordagem aproveita os pontos fortes do Cassandra, mantendo a compatibilidade total da API, garantindo que o código existente se beneficie automaticamente das melhorias de desempenho. diff --git a/docs/tech-specs/cassandra-performance-refactor.ru.md b/docs/tech-specs/cassandra-performance-refactor.ru.md new file mode 100644 index 00000000..97d0fa43 --- /dev/null +++ b/docs/tech-specs/cassandra-performance-refactor.ru.md @@ -0,0 +1,679 @@ +# Технические спецификации: Оптимизация производительности базы знаний Cassandra + +**Статус:** Черновик +**Автор:** Ассистент +**Дата:** 2025-09-18 + +## Обзор + +Данная спецификация рассматривает проблемы производительности в реализации базы знаний TrustGraph на Cassandra и предлагает оптимизации для хранения и запросов RDF-тройных. + +## Текущая реализация + +### Структура данных + +Текущая реализация использует структуру данных с одной таблицей в `trustgraph-flow/trustgraph/direct/cassandra_kg.py`: + +```sql +CREATE TABLE triples ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` + +**Вторичные индексы:** +`triples_s` по `s` (субъект) +`triples_p` по `p` (предикат) +`triples_o` по `o` (объект) + +### Шаблоны запросов + +Текущая реализация поддерживает 8 различных шаблонов запросов: + +1. **get_all(collection, limit=50)** - Получить все тройки для коллекции + ```sql + SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50 + ``` + +2. **get_s(collection, s, limit=10)** - Запрос по теме. + ```sql + SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10 + ``` + +3. **get_p(collection, p, limit=10)** - Запрос по предикату. + ```sql + SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10 + ``` + +4. **get_o(collection, o, limit=10)** - Запрос по объекту. + ```sql + SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10 + ``` + +5. **get_sp(collection, s, p, limit=10)** - Запрос по субъекту + предикату. + ```sql + SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10 + ``` + +6. **get_po(collection, p, o, limit=10)** - Запрос по предикату + объекту ⚠️ + ```sql + SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING + ``` + +7. **get_os(collection, o, s, limit=10)** - Запрос по объекту + субъекту ⚠️ + ```sql + SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING + ``` + +8. **get_spo(collection, s, p, o, limit=10)** - Точное соответствие тройке. + ```sql + SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10 + ``` + +### Текущая архитектура + +**Файл: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`** +Один класс `KnowledgeGraph`, обрабатывающий все операции +Объединение подключений через глобальный список `_active_clusters` +Фиксированное имя таблицы: `"triples"` +Пространство ключей для каждой модели пользователя +Репликация SimpleStrategy с коэффициентом 1 + +**Точки интеграции:** +**Путь записи:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +**Путь запроса:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` +**Хранилище знаний:** `trustgraph-flow/trustgraph/tables/knowledge.py` + +## Выявленные проблемы с производительностью + +### Проблемы на уровне схемы + +1. **Неэффективный дизайн первичного ключа** + Текущий: `PRIMARY KEY (collection, s, p, o)` + Приводит к плохой кластеризации для распространенных шаблонов доступа + Заставляет использовать дорогостоящие вторичные индексы + +2. **Чрезмерное использование вторичных индексов** ⚠️ + Три вторичных индекса на столбцах с высокой кардинальностью (s, p, o) + Вторичные индексы в Cassandra дороги и плохо масштабируются + Запросы 6 и 7 требуют `ALLOW FILTERING`, что указывает на плохое моделирование данных + +3. **Риск "горячих" разделов** + Один ключ раздела `collection` может создавать "горячие" разделы + Большие коллекции будут концентрироваться на отдельных узлах + Отсутствует стратегия распределения для балансировки нагрузки + +### Проблемы на уровне запросов + +1. **Использование ALLOW FILTERING** ⚠️ + Два типа запросов (get_po, get_os) требуют `ALLOW FILTERING` + Эти запросы сканируют несколько разделов и чрезвычайно дороги + Производительность ухудшается линейно с увеличением объема данных + +2. **Неэффективные шаблоны доступа** + Отсутствует оптимизация для распространенных шаблонов запросов RDF + Отсутствуют составные индексы для часто используемых комбинаций запросов + Не учитываются шаблоны обхода графов + +3. **Отсутствие оптимизации запросов** + Отсутствует кэширование подготовленных выражений + Отсутствуют подсказки или стратегии оптимизации запросов + Не учитывается постраничная навигация, кроме простого LIMIT + +## Описание проблемы + +Текущая реализация базы знаний Cassandra имеет два критических узких места в производительности: + +### 1. Неэффективная производительность запроса get_po + +Запрос `get_po(collection, p, o)` крайне неэффективен, поскольку требует `ALLOW FILTERING`: + +```sql +SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING +``` + +**Почему это является проблемой:** +`ALLOW FILTERING` заставляет Cassandra сканировать все разделы внутри коллекции. +Производительность ухудшается линейно с увеличением размера данных. +Это распространенный шаблон запросов RDF (поиск объектов, имеющих определенную связь "субъект-предикат-объект"). +Это создает значительную нагрузку на кластер по мере роста данных. + +### 2. Неоптимальная стратегия кластеризации + +Текущий первичный ключ `PRIMARY KEY (collection, s, p, o)` обеспечивает минимальные преимущества кластеризации: + +**Проблемы с текущей кластеризацией:** +`collection` в качестве ключа раздела не обеспечивает эффективное распределение данных. +Большинство коллекций содержат разнообразные данные, что делает кластеризацию неэффективной. +Отсутствует учет типичных шаблонов доступа в запросах RDF. +Большие коллекции создают "горячие" разделы на отдельных узлах. +Столбцы кластеризации (s, p, o) не оптимизированы для типичных шаблонов обхода графа. + +**Влияние:** +Запросы не получают выгоды от локальности данных. +Плохое использование кэша. +Неравномерное распределение нагрузки между узлами кластера. +"Узкие места" масштабируемости по мере роста коллекций. + +## Предлагаемое решение: Стратегия денормализации с использованием 4 таблиц + +### Обзор + +Замените одну таблицу `triples` на четыре специализированные таблицы, каждая из которых оптимизирована для конкретных шаблонов запросов. Это устраняет необходимость во вторичных индексах и использовании ALLOW FILTERING, обеспечивая при этом оптимальную производительность для всех типов запросов. Четвертая таблица обеспечивает эффективное удаление коллекций, несмотря на составные ключи разделов. + +### Новая структура схемы + +**Таблица 1: Запросы, ориентированные на субъекты (triples_s)** +```sql +CREATE TABLE triples_s ( + collection text, + s text, + p text, + o text, + PRIMARY KEY ((collection, s), p, o) +); +``` +**Оптимизирует:** get_s, get_sp, get_os +**Ключ разделения:** (collection, s) - Обеспечивает лучшую распределенность, чем только collection. +**Кластеризация:** (p, o) - Обеспечивает эффективный поиск по предикатам/объектам для субъекта. + +**Таблица 2: Запросы предикат-объект (triples_p)** +```sql +CREATE TABLE triples_p ( + collection text, + p text, + o text, + s text, + PRIMARY KEY ((collection, p), o, s) +); +``` +**Оптимизирует:** get_p, get_po (исключает ALLOW FILTERING!) +**Ключ партиции:** (collection, p) - Прямой доступ по предикату +**Кластеризация:** (o, s) - Эффективный обход объектов и субъектов + +**Таблица 3: Объектно-ориентированные запросы (triples_o)** +```sql +CREATE TABLE triples_o ( + collection text, + o text, + s text, + p text, + PRIMARY KEY ((collection, o), s, p) +); +``` +**Оптимизирует:** get_o +**Ключ разделения:** (collection, o) - Прямой доступ по объекту +**Кластеризация:** (s, p) - Эффективный обход по субъекту-предикату + +**Таблица 4: Управление коллекциями и запросы SPO (triples_collection)** +```sql +CREATE TABLE triples_collection ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` +**Оптимизирует:** get_spo, delete_collection +**Разделительный ключ:** только коллекция - Обеспечивает эффективные операции на уровне коллекций. +**Кластеризация:** (s, p, o) - Стандартный порядок троек. +**Назначение:** Двойное использование для точного поиска SPO и в качестве индекса удаления. + +### Отображение запросов + +| Исходный запрос | Целевая таблица | Улучшение производительности | +|----------------|-------------|------------------------| +| get_all(collection) | triples_s | ALLOW FILTERING (приемлемо для сканирования) | +| get_s(collection, s) | triples_s | Прямой доступ к разделу | +| get_p(collection, p) | triples_p | Прямой доступ к разделу | +| get_o(collection, o) | triples_o | Прямой доступ к разделу | +| get_sp(collection, s, p) | triples_s | Раздел + кластеризация | +| get_po(collection, p, o) | triples_p | **Больше не требуется ALLOW FILTERING!** | +| get_os(collection, o, s) | triples_o | Раздел + кластеризация | +| get_spo(collection, s, p, o) | triples_collection | Точный поиск по ключу | +| delete_collection(collection) | triples_collection | Чтение индекса, пакетное удаление всех | + +### Стратегия удаления коллекций + +С составными раздельными ключами мы не можем просто выполнить `DELETE FROM table WHERE collection = ?`. Вместо этого: + +1. **Фаза чтения:** Запрос `triples_collection` для перечисления всех троек: + ```sql + SELECT s, p, o FROM triples_collection WHERE collection = ? + ``` + Это эффективно, поскольку `collection` является ключом секции для этой таблицы. + +2. **Фаза удаления:** Для каждой тройки (s, p, o) удалите из всех 4 таблиц, используя полные ключи секций: + ```sql + DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ? + DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ? + DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ? + DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ? + ``` + Обрабатывается пакетами по 100 элементов для повышения эффективности. + +**Анализ компромиссов:** +✅ Поддерживает оптимальную производительность запросов с использованием распределенных разделов. +✅ Отсутствуют "горячие" разделы для больших коллекций. +❌ Более сложная логика удаления (чтение, а затем удаление). +❌ Время удаления пропорционально размеру коллекции. + +### Преимущества + +1. **Устраняет ALLOW FILTERING** - Каждый запрос имеет оптимальный путь доступа (за исключением полного сканирования). +2. **Не требуются вторичные индексы** - Каждая таблица ЯВЛЯЕТСЯ индексом для своего шаблона запросов. +3. **Более равномерное распределение данных** - Композитные ключи разделов эффективно распределяют нагрузку. +4. **Предсказуемая производительность** - Время выполнения запроса пропорционально размеру результата, а не общему объему данных. +5. **Использует сильные стороны Cassandra** - Разработана с учетом архитектуры Cassandra. +6. **Позволяет удалять коллекции** - `triples_collection` служит индексом для удаления. + +## План реализации + +### Файлы, требующие изменений + +#### Основной файл реализации + +**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - Требуется полная переработка. + +**Методы, требующие рефакторинга:** +```python +# Schema initialization +def init(self) -> None # Replace single table with three tables + +# Insert operations +def insert(self, collection, s, p, o) -> None # Write to all three tables + +# Query operations (API unchanged, implementation optimized) +def get_all(self, collection, limit=50) # Use triples_by_subject +def get_s(self, collection, s, limit=10) # Use triples_by_subject +def get_p(self, collection, p, limit=10) # Use triples_by_po +def get_o(self, collection, o, limit=10) # Use triples_by_object +def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject +def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!) +def get_os(self, collection, o, s, limit=10) # Use triples_by_subject +def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject + +# Collection management +def delete_collection(self, collection) -> None # Delete from all three tables +``` + +#### Интеграционные файлы (изменения в логике не требуются) + +**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`** +Изменения не требуются - используется существующий API KnowledgeGraph. +Автоматически получает преимущества от улучшений производительности. + +**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`** +Изменения не требуются - используется существующий API KnowledgeGraph. +Автоматически получает преимущества от улучшений производительности. + +### Файлы для тестирования, требующие обновления + +#### Юнит-тесты +**`tests/unit/test_storage/test_triples_cassandra_storage.py`** +Обновить ожидаемые результаты тестов в связи с изменениями схемы. +Добавить тесты для обеспечения согласованности между несколькими таблицами. +Проверить отсутствие использования ALLOW FILTERING в планах запросов. + +**`tests/unit/test_query/test_triples_cassandra_query.py`** +Обновить утверждения о производительности. +Протестировать все 8 шаблонов запросов для новых таблиц. +Проверить маршрутизацию запросов к правильным таблицам. + +#### Интеграционные тесты +**`tests/integration/test_cassandra_integration.py`** +Комплексное тестирование с новой схемой. +Сравнение результатов бенчмаркинга производительности. +Проверка согласованности данных между таблицами. + +**`tests/unit/test_storage/test_cassandra_config_integration.py`** +Обновить тесты проверки схемы. +Протестировать сценарии миграции. + +### Стратегия реализации + +#### Фаза 1: Схема и основные методы +1. **Переписать метод `init()`** - Создать четыре таблицы вместо одной. +2. **Переписать метод `insert()`** - Выполнять пакетные записи во все четыре таблицы. +3. **Реализовать подготовленные запросы** - Для оптимальной производительности. +4. **Добавить логику маршрутизации таблиц** - Направлять запросы к оптимальным таблицам. +5. **Реализовать удаление коллекций** - Читать из triples_collection, пакетно удалять из всех таблиц. + +#### Фаза 2: Оптимизация методов запросов +1. **Переписать каждый метод get_*** для использования оптимальной таблицы. +2. **Удалить все случаи использования ALLOW FILTERING**. +3. **Реализовать эффективное использование ключей кластеризации**. +4. **Добавить логирование производительности запросов**. + +#### Фаза 3: Управление коллекциями +1. **Обновить `delete_collection()`** - Удалить из всех трех таблиц. +2. **Добавить проверку согласованности** - Обеспечить синхронизацию всех таблиц. +3. **Реализовать пакетные операции** - Для атомарных операций с несколькими таблицами. + +### Ключевые детали реализации + +#### Стратегия пакетной записи +```python +def insert(self, collection, s, p, o): + batch = BatchStatement() + + # Insert into all four tables + batch.add(self.insert_subject_stmt, (collection, s, p, o)) + batch.add(self.insert_po_stmt, (collection, p, o, s)) + batch.add(self.insert_object_stmt, (collection, o, s, p)) + batch.add(self.insert_collection_stmt, (collection, s, p, o)) + + self.session.execute(batch) +``` + +#### Логика маршрутизации запросов +```python +def get_po(self, collection, p, o, limit=10): + # Route to triples_p table - NO ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) + +def get_spo(self, collection, s, p, o, limit=10): + # Route to triples_collection table for exact SPO lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) +``` + +#### Логика удаления коллекции +```python +def delete_collection(self, collection): + # Step 1: Read all triples from collection table + rows = self.session.execute( + f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s", + (collection,) + ) + + # Step 2: Batch delete from all 4 tables + batch = BatchStatement() + count = 0 + + for row in rows: + s, p, o = row.s, row.p, row.o + + # Delete using full partition keys for each table + batch.add(SimpleStatement( + f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?" + ), (collection, p, o, s)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?" + ), (collection, o, s, p)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + count += 1 + + # Execute every 100 triples to avoid oversized batches + if count % 100 == 0: + self.session.execute(batch) + batch = BatchStatement() + + # Execute remaining deletions + if count % 100 != 0: + self.session.execute(batch) + + logger.info(f"Deleted {count} triples from collection {collection}") +``` + +#### Оптимизация подготовленных выражений +```python +def prepare_statements(self): + # Cache prepared statements for better performance + self.insert_subject_stmt = self.session.prepare( + f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + self.insert_po_stmt = self.session.prepare( + f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)" + ) + self.insert_object_stmt = self.session.prepare( + f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)" + ) + self.insert_collection_stmt = self.session.prepare( + f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + # ... query statements +``` + +## Стратегия миграции + +### Подход к миграции данных + +#### Вариант 1: Развертывание Blue-Green (Рекомендуется) +1. **Разверните новую схему параллельно с существующей** - Временно используйте разные имена таблиц. +2. **Период двойной записи** - Записывайте данные как в старую, так и в новую схемы во время перехода. +3. **Фоновая миграция** - Скопируйте существующие данные в новые таблицы. +4. **Перенаправление операций чтения** - Направляйте запросы к новым таблицам после миграции данных. +5. **Удаление старых таблиц** - После периода проверки. + +#### Вариант 2: Миграция на месте +1. **Добавление схемы** - Создайте новые таблицы в существующем пространстве ключей. +2. **Скрипт миграции данных** - Пакетная копия из старой таблицы в новые таблицы. +3. **Обновление приложения** - Разверните новый код после завершения миграции. +4. **Очистка старой таблицы** - Удалите старую таблицу и индексы. + +### Обратная совместимость + +#### Стратегия развертывания +```python +# Environment variable to control table usage during migration +USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' + +class KnowledgeGraph: + def __init__(self, ...): + if USE_LEGACY_TABLES: + self.init_legacy_schema() + else: + self.init_optimized_schema() +``` + +#### Скрипт миграции +```python +def migrate_data(): + # Read from old table + old_triples = session.execute("SELECT collection, s, p, o FROM triples") + + # Batch write to new tables + for batch in batched(old_triples, 100): + batch_stmt = BatchStatement() + for row in batch: + # Add to all three new tables + batch_stmt.add(insert_subject_stmt, row) + batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s)) + batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p)) + session.execute(batch_stmt) +``` + +### Стратегия проверки + +#### Проверки согласованности данных +```python +def validate_migration(): + # Count total records in old vs new tables + old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,)) + new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,)) + + assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}" + + # Spot check random samples + sample_queries = generate_test_queries() + for query in sample_queries: + old_result = execute_legacy_query(query) + new_result = execute_optimized_query(query) + assert old_result == new_result, f"Query results differ for {query}" +``` + +## Стратегия тестирования + +### Тестирование производительности + +#### Сценарии для бенчмаркинга +1. **Сравнение производительности запросов** + Показатели производительности до и после для всех 8 типов запросов + Акцент на улучшении производительности запроса `get_po` (удаление `ALLOW FILTERING`) + Измерение задержки запросов при различных объемах данных + +2. **Тестирование нагрузки** + Одновременное выполнение запросов + Скорость записи с использованием пакетных операций + Использование памяти и ЦП + +3. **Тестирование масштабируемости** + Производительность при увеличении размеров коллекций + Распределение запросов по нескольким коллекциям + Использование узлов кластера + +#### Наборы тестовых данных +**Маленький:** 10 тысяч троек на коллекцию +**Средний:** 100 тысяч троек на коллекцию +**Большой:** 1 миллион и более троек на коллекцию +**Несколько коллекций:** Тестирование распределения партиций + +### Функциональное тестирование + +#### Обновления модульных тестов +```python +# Example test structure for new implementation +class TestCassandraKGPerformance: + def test_get_po_no_allow_filtering(self): + # Verify get_po queries don't use ALLOW FILTERING + with patch('cassandra.cluster.Session.execute') as mock_execute: + kg.get_po('test_collection', 'predicate', 'object') + executed_query = mock_execute.call_args[0][0] + assert 'ALLOW FILTERING' not in executed_query + + def test_multi_table_consistency(self): + # Verify all tables stay in sync + kg.insert('test', 's1', 'p1', 'o1') + + # Check all tables contain the triple + assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1') + assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1') + assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1') +``` + +#### Обновления результатов интеграционного тестирования +```python +class TestCassandraIntegration: + def test_query_performance_regression(self): + # Ensure new implementation is faster than old + old_time = benchmark_legacy_get_po() + new_time = benchmark_optimized_get_po() + assert new_time < old_time * 0.5 # At least 50% improvement + + def test_end_to_end_workflow(self): + # Test complete write -> query -> delete cycle + # Verify no performance degradation in integration +``` + +### План отката + +#### Быстрая стратегия отката +1. **Переключение переменной окружения** - Немедленный возврат к устаревшим таблицам. +2. **Сохранение устаревших таблиц** - Не удалять до тех пор, пока производительность не будет подтверждена. +3. **Сигналы мониторинга** - Автоматический запуск отката на основе показателей ошибок/задержек. + +#### Проверка отката +```python +def rollback_to_legacy(): + # Set environment variable + os.environ['CASSANDRA_USE_LEGACY'] = 'true' + + # Restart services to pick up change + restart_cassandra_services() + + # Validate functionality + run_smoke_tests() +``` + +## Риски и соображения + +### Риски производительности +**Увеличение времени записи** - 4 операции записи на каждую вставку (на 33% больше, чем при использовании 3-х таблиц) +**Избыточность хранения** - В 4 раза больше места для хранения (на 33% больше, чем при использовании 3-х таблиц) +**Сбои пакетной записи** - Требуется правильная обработка ошибок +**Сложность удаления** - Удаление коллекции требует цикла "чтение-удаление" + +### Операционные риски +**Сложность миграции** - Миграция данных для больших наборов данных +**Проблемы с согласованностью** - Обеспечение синхронизации всех таблиц +**Недостаточность мониторинга** - Необходимы новые метрики для операций с несколькими таблицами + +### Стратегии смягчения +1. **Постепенное внедрение** - Начните с небольших коллекций +2. **Комплексный мониторинг** - Отслеживайте все метрики производительности +3. **Автоматизированная проверка** - Постоянная проверка согласованности +4. **Возможность быстрого отката** - Выбор таблицы на основе среды + +## Критерии успеха + +### Улучшения производительности +[ ] **Устранение ALLOW FILTERING** - Запросы get_po и get_os выполняются без фильтрации +[ ] **Сокращение задержки запросов** - Улучшение времени отклика запросов на 50% или более +[ ] **Более равномерное распределение нагрузки** - Отсутствие "горячих" партиций, равномерная нагрузка на узлы кластера +[ ] **Масштабируемая производительность** - Время запроса пропорционально размеру результата, а не общему объему данных + +### Функциональные требования +[ ] **Совместимость API** - Весь существующий код продолжает работать без изменений +[ ] **Согласованность данных** - Все три таблицы остаются синхронизированными +[ ] **Отсутствие потери данных** - Миграция сохраняет все существующие тройки +[ ] **Обратная совместимость** - Возможность отката к устаревшей схеме + +### Операционные требования +[ ] **Безопасная миграция** - Развертывание по принципу "синий-зеленый" с возможностью отката +[ ] **Покрытие мониторингом** - Комплексные метрики для операций с несколькими таблицами +[ ] **Покрытие тестами** - Все шаблоны запросов протестированы с использованием эталонных показателей производительности +[ ] **Документация** - Обновленные процедуры развертывания и эксплуатации + +## План + +### Фаза 1: Реализация +[ ] Переписать `cassandra_kg.py` с использованием схемы нескольких таблиц +[ ] Реализовать пакетные операции записи +[ ] Добавить оптимизацию с использованием подготовленных выражений +[ ] Обновить модульные тесты + +### Фаза 2: Интеграционное тестирование +[ ] Обновить интеграционные тесты +[ ] Эталонное тестирование производительности +[ ] Тестирование нагрузки с использованием реалистичных объемов данных +[ ] Скрипты проверки согласованности данных + +### Фаза 3: Планирование миграции +[ ] Скрипты развертывания по принципу "синий-зеленый" +[ ] Инструменты миграции данных +[ ] Обновления панели мониторинга +[ ] Процедуры отката + +### Фаза 4: Развертывание в производственной среде +[ ] Поэтапное развертывание в производственной среде +[ ] Мониторинг и проверка производительности +[ ] Очистка устаревших таблиц +[ ] Обновление документации + +## Заключение + +Эта стратегия денормализации с использованием нескольких таблиц напрямую решает две критические проблемы производительности: + +1. **Устраняет дорогостоящий ALLOW FILTERING**, предоставляя оптимальные структуры таблиц для каждого шаблона запроса +2. **Улучшает эффективность кластеризации** за счет составных ключей партиций, которые правильно распределяют нагрузку + +Этот подход использует сильные стороны Cassandra, сохраняя при этом полную совместимость API, что обеспечивает автоматическое получение преимуществ от улучшений производительности для существующего кода. diff --git a/docs/tech-specs/cassandra-performance-refactor.sw.md b/docs/tech-specs/cassandra-performance-refactor.sw.md new file mode 100644 index 00000000..7b889262 --- /dev/null +++ b/docs/tech-specs/cassandra-performance-refactor.sw.md @@ -0,0 +1,679 @@ +# Maelezo ya Kiufundi: Uboreshaji wa Utendaji wa Hifadhidata ya Maarifa ya Cassandra + +**Hali:** Rasimu +**Mwandishi:** Msaidizi +**Tarehe:** 2025-09-18 + +## Muhtasari + +Maelezo haya yanashughulikia masuala ya utendaji katika utekelezaji wa hifadhidata ya maarifa ya TrustGraph ya Cassandra na yanapendekeza uboreshaji kwa uhifadhi na utafutaji wa data ya RDF. + +## Utendaji wa Sasa + +### Muundo wa Skimu + +Utendaji wa sasa hutumia muundo wa jedwali moja katika `trustgraph-flow/trustgraph/direct/cassandra_kg.py`: + +```sql +CREATE TABLE triples ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` + +**Faharasa Pili:** +`triples_s` KWA `s` (somo) +`triples_p` KWA `p` (kitenzi) +`triples_o` KWA `o` (kielele) + +### Mifumo ya Umasiliano + +Utaratibu wa sasa unaoendeshwa unao na mifumo 8 tofauti ya masiliano: + +1. **get_all(mkusanyiko, kikomo=50)** - Pata vitriple vyote kwa mkusanyiko + ```sql + SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50 + ``` + +2. **get_s(collection, s, limit=10)** - Utafiti kwa mada. + ```sql + SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10 + ``` + +3. **get_p(collection, p, limit=10)** - Utafiti kwa kutumia vigezo. + ```sql + SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10 + ``` + +4. **get_o(collection, o, limit=10)** - Utafiti kwa kutumia kitu. + ```sql + SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10 + ``` + +5. **get_sp(collection, s, p, limit=10)** - Utafiti kwa mada + predikati + ```sql + SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10 + ``` + +6. **get_po(collection, p, o, limit=10)** - Utafiti kwa kutumia vigezo na kitu ⚠️ + ```sql + SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING + ``` + +7. **get_os(collection, o, s, limit=10)** - Utafiti kwa kutumia kitu pamoja na mada ⚠️ + ```sql + SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING + ``` + +8. **get_spo(collection, s, p, o, limit=10)** - Mechi kamili ya triple. + ```sql + SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10 + ``` + +### Muundo wa Sasa + +**Faili: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`** +Darasa moja la `KnowledgeGraph` linaloshughulikia shughuli zote +Uunganisho wa kikundi kupitia orodha ya kimataifa ya `_active_clusters` +Jina la jedwali lililobainishwa: `"triples"` +Spishi kwa kila mfumo wa mtumiaji +Nakala ya SimpleStrategy kwa sababu 1 + +**Maeneo ya Uunganisho:** +**Njia ya Kuandika:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +**Njia ya Umasilisho:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` +**Hifadhi ya Maarifa:** `trustgraph-flow/trustgraph/tables/knowledge.py` + +## Matatizo ya Utendaji Yanayobainika + +### Matatizo ya Ngazi ya Muundo + +1. **Muundo Usiofaa wa Ufunguo Mkuu** + Sasa: `PRIMARY KEY (collection, s, p, o)` + Hupelekea uwekaji duni wa data kwa mifumo ya kawaida ya ufikiaji + Inahitaji matumizi ya gharama kubwa ya fahirisi za sekondari + +2. **Matumizi Mengi ya Fahirisi za Sekondari** ⚠️ + Fahirisi tatu za sekondari kwenye safu zenye maadili mengi (s, p, o) + Fahirisi za sekondari katika Cassandra ni ghali na hazipunguzi kasi vizuri + Maswali 6 na 7 yanahitaji `ALLOW FILTERING`, ambayo inaonyesha muundo duni wa data + +3. **Hatari ya Sehemu Zenye Trafiki Kubwa** + Ufunguo mmoja wa sehemu `collection` unaweza kuunda sehemu zenye trafiki kubwa + Mkusanyiko mkubwa utajikuta katika nodi moja + Hakuna mkakati wa usambazaji wa mizigo + +### Matatizo ya Ngazi ya Umasilisho + +1. **Matumizi ya ALLOW FILTERING** ⚠️ + Aina mbili za maswali (get_po, get_os) zinahitaji `ALLOW FILTERING` + Maswali haya husifia sehemu nyingi na ni ghali sana + Utendaji unapungua kwa kasi kadri ya ukubwa wa data + +2. **Mifumo ya Ufikiaji Yasiyo na Ufanisi** + Hakuna uboreshaji kwa mifumo ya kawaida ya maswali ya RDF + Hakuna fahirisi za pamoja kwa mchanganyiko wa maswali unaoonekana mara kwa mara + Hakuna utambuzi wa mifumo ya utaftaji wa grafu + +3. **Ukosefu wa Uboreshaji wa Umasilisho** + Hakuna kuhifadhi kwa masimulizi yaliyotayarishwa + Hakuna vidokezo au mikakati ya uboreshaji wa maswali + Hakuna utambuzi wa upangishaji zaidi ya LIMIT rahisi + +## Taarifa ya Tatizo + +Utekelezaji wa sasa wa hifadhi ya maarifa ya Cassandra una matatizo mawili muhimu ya utendaji: + +### 1. Utendaji Usio na Ufanisi wa Maswali ya get_po + +Swali la `get_po(collection, p, o)` halipunguzi kasi kwa sababu linahitaji `ALLOW FILTERING`: + +```sql +SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING +``` + +**Sababu ya kuwa hii ni tatizo:** +`ALLOW FILTERING` inalazimisha Cassandra kuchanganua kila sehemu ndani ya mkusanyiko. +Utendaji hupungua kwa mstari sawa na ukubwa wa data. +Hii ni muundo wa kawaida wa swali la RDF (kutafuta vitu ambavyo vina uhusiano maalum wa tabia-jambo). +Huunda mzigo mkubwa kwenye kundi kadri data inavyoongezeka. + +### 2. Mkakati Usiofaa wa Uwekaji Pamoja + +Ufunguo mkuu wa sasa `PRIMARY KEY (collection, s, p, o)` hutoa faida ndogo katika uwekaji pamoja: + +**Matatizo na uwekaji pamoja wa sasa:** +`collection` kama funguo ya sehemu haisambati data kwa ufanisi. +Makusanyiko mengi yana data tofauti, na kuifanya uwekaji pamoja kuwa usiofaa. +Hakuna utambuzi kwa mifumo ya kawaida ya ufikiaji katika maswali ya RDF. +Makusanyiko makubwa huunda sehemu zenye mzigo mwingi kwenye nodi moja. +Safu za uwekaji pamoja (s, p, o) haziboreshi kwa mifumo ya kawaida ya utaftaji wa grafu. + +**Athari:** +Maswali hayanapata faida kutoka kwa ukaribu wa data. +Matumizi duni ya kumbukumbu (cache). +Usambazaji usio sawa wa mzigo katika nodi za kundi. +Zuio la uwezo wa kupanuka (scalability) kadri makusanyiko yanavyoongezeka. + +## Suluhisho Lililopendekezwa: Mkakati wa Utofauti wa Jedwali 4 + +### Muhtasari + +Badilisha jedwali moja `triples` na jedwali nne zilizoundwa kwa madhumuni maalum, kila moja iliyoboreshwa kwa mifumo maalum ya swali. Hii inafutilia hitaji la fahirisi za sekondari na ALLOW FILTERING huku ikiwapa utendaji bora kwa aina zote za swali. Jedwali la nne linaruhusu uondoaji wa makusanyiko kwa ufanisi licha ya funguo za sehemu zilizounganishwa. + +### Muundo Mpya wa Skimu + +**Jedwali la 1: Maswali Yanayozingatia Sijali (triples_s)** +```sql +CREATE TABLE triples_s ( + collection text, + s text, + p text, + o text, + PRIMARY KEY ((collection, s), p, o) +); +``` +**Inaboresha:** get_s, get_sp, get_os +**Ufunguo wa Sehemu:** (mkusanyiko, s) - Usambazaji bora kuliko mkusanyiko pekee +**Kukusanya:** (p, o) - Huwezesha utafutaji wa ufanisi wa vigezo/vitendo kwa ajili ya somo + +**Jedwali 2: Maswali ya Vigezo-Vitendo (triples_p)** +```sql +CREATE TABLE triples_p ( + collection text, + p text, + o text, + s text, + PRIMARY KEY ((collection, p), o, s) +); +``` +**Inaboresha:** get_p, get_po (inabadilisha ALLOW FILTERING!) +**Ufunguo wa Sehemu:** (mkusanyiko, p) - Ufikiaji wa moja kwa moja kupitia kigezo. +**Kukusanyika:** (o, s) - Ufuatiliaji wa vitu na masomo unaofaa. + +**Jedwali la 3: Maswali Yanayozingatia Vitu (triples_o)** +```sql +CREATE TABLE triples_o ( + collection text, + o text, + s text, + p text, + PRIMARY KEY ((collection, o), s, p) +); +``` +**Inaboresha:** get_o +**Ufunguo wa Sehemu:** (mkusanyiko, o) - Ufikiaji wa moja kwa moja kwa kutumia kitu +**Kukusanya:** (s, p) - Ufuatiliaji wa ufanisi wa somo-tabia + +**Jedwali la 4: Usimamizi wa Mkusaniko na Maswali ya SPO (triples_collection)** +```sql +CREATE TABLE triples_collection ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` +**Inaboresha:** get_spo, delete_collection +**Ufunguo wa Sehemu (Partition Key):** mkusanyiko pekee - Huwezesha operesheni bora za kiwango cha mkusanyiko. +**Kukusanyika (Clustering):** (s, p, o) - Mpangilio wa kawaida wa triple. +**Madhumuni:** Matumizi mawili, kwa utafutaji sahihi wa SPO na kama faharasa ya kufuta. + +### Ramani ya Utafutaji (Query Mapping) + +| Utafutaji Asili | Jedwali Linalolengwa | Ubora wa Kuboresha | +|----------------|-------------|------------------------| +| get_all(collection) | triples_s | RUHASA YA KUCHANUA (inayokubalika kwa skani) | +| get_s(collection, s) | triples_s | Ufikiaji wa moja kwa moja wa sehemu. | +| get_p(collection, p) | triples_p | Ufikiaji wa moja kwa moja wa sehemu. | +| get_o(collection, o) | triples_o | Ufikiaji wa moja kwa moja wa sehemu. | +| get_sp(collection, s, p) | triples_s | Sehemu + kukusanyika. | +| get_po(collection, p, o) | triples_p | **HAKUNA tena RUHASA LA KUCHANUA!** | +| get_os(collection, o, s) | triples_o | Sehemu + kukusanyika. | +| get_spo(collection, s, p, o) | triples_collection | Utafutaji wa ufunguo wa moja kwa moja. | +| delete_collection(collection) | triples_collection | Soma faharasa, futa kwa wingi. | + +### Mkakati wa Kufuta Mkusaniko + +Pamoja na ufunguo wa sehemu mchanganyiko, hatuwezi tu kutekeleza `DELETE FROM table WHERE collection = ?`. Badala yake: + +1. **Awamu ya Kusoma:** Tafuta `triples_collection` ili kuorodhesha triple zote: + ```sql + SELECT s, p, o FROM triples_collection WHERE collection = ? + ``` + Hii ni bora kwa sababu `collection` ndiyo ufunguo wa kundi kwa jedwali hili. + +2. **Awamu ya Ufutilishaji:** Kwa kila seti tatu (s, p, o), futa kutoka kwenye meza zote 4 kwa kutumia ufunguo kamili wa kundi: + ```sql + DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ? + DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ? + DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ? + DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ? + ``` + Imefunganishwa katika makundi ya 100 ili kuongeza ufanisi. + +**Uchambuzi wa Usawa:** +✅ Inaendelea kudumisha utendaji bora wa maswali kwa kutumia vipande vilivyogawanywa. +✅ Hakuna vipande ambavyo hupita kasi kwa makusanyo makubwa. +❌ Mantiki ya kufuta ni ngumu zaidi (soma kisha futa). +❌ Muda wa kufuta unalingana na ukubwa wa mkusanyiko. + +### Faida + +1. **Inaondoa ALLOW FILTERING** - Kila swali lina njia bora ya kufikia (isipokuwa skani ya get_all). +2. **Hakuna Faharasa za Pili** - Kila jedwali NI faharasa kwa mtindo wake wa swali. +3. **Usambazaji Bora wa Data** - Funguo za pamoja za kugawanya zinapanua mzigo kwa ufanisi. +4. **Utendaji Unaoweza Kushawishiwa** - Muda wa swali unalingana na ukubwa wa matokeo, sio data jumla. +5. **Inatumia Nguvu za Cassandra** - Imeundwa kwa usanifu wa Cassandra. +6. **Inaruhusu Ufuta wa Makusanyo** - triples_collection hutumika kama faharasa ya kufuta. + +## Mpango wa Utendaji + +### Faili Zinazohitaji Marekebisho + +#### Faili Kuu ya Utendaji + +**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - Inahitajika kuandikwa upya kabisa. + +**Mbinu Zinazohitajika Kubadilishwa:** +```python +# Schema initialization +def init(self) -> None # Replace single table with three tables + +# Insert operations +def insert(self, collection, s, p, o) -> None # Write to all three tables + +# Query operations (API unchanged, implementation optimized) +def get_all(self, collection, limit=50) # Use triples_by_subject +def get_s(self, collection, s, limit=10) # Use triples_by_subject +def get_p(self, collection, p, limit=10) # Use triples_by_po +def get_o(self, collection, o, limit=10) # Use triples_by_object +def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject +def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!) +def get_os(self, collection, o, s, limit=10) # Use triples_by_subject +def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject + +# Collection management +def delete_collection(self, collection) -> None # Delete from all three tables +``` + +#### Faili za Uunganishaji (Hakuna Mabadiliko ya Mantiki Yanayohitajika) + +**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`** +Hakuna mabadiliko yanayohitajika - hutumia API ya KnowledgeGraph iliyopo +Inafaidika moja kwa moja kutoka kwa uboreshaji wa utendaji + +**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`** +Hakuna mabadiliko yanayohitajika - hutumia API ya KnowledgeGraph iliyopo +Inafaidika moja kwa moja kutoka kwa uboreshaji wa utendaji + +### Faili za Majaribio Zinazohitaji Mabadiliko + +#### Majaribio ya Kitengo +**`tests/unit/test_storage/test_triples_cassandra_storage.py`** +Sasisha matarajio ya majaribio kwa mabadiliko ya schema +Ongeza majaribio kwa utangamano wa meza nyingi +Hakikisha hakuna ALLOW FILTERING katika mipango ya swali + +**`tests/unit/test_query/test_triples_cassandra_query.py`** +Sasisha madai ya utendaji +Jaribu mifumo yote 8 ya swali dhidi ya meza mpya +Hakikisha uelekezaji wa swali hadi meza sahihi + +#### Majaribio ya Uunganishaji +**`tests/integration/test_cassandra_integration.py`** +Majaribio ya mwisho na schema mpya +Ulinganisho wa benchmarking wa utendaji +Uthibitisho wa utangamano wa data katika meza + +**`tests/unit/test_storage/test_cassandra_config_integration.py`** +Sasisha majaribio ya uthibitisho wa schema +Jaribu hali za uhamishaji + +### Mkakati wa Utendaji + +#### Awamu ya 1: Schema na Mbinu za Msingi +1. **Andika upya mbinu ya `init()`** - Unda meza nne badala ya moja +2. **Andika upya mbinu ya `insert()`** - Andika kwa wingi kwenye meza zote nne +3. **Teleza taarifa zilizotayarishwa** - Kwa utendaji bora +4. **Ongeza mantiki ya uelekezaji wa meza** - Elekeza maswali hadi meza bora +5. **Teleza uondoaji wa mkusanyiko** - Soma kutoka kwa triples_collection, ondoa kwa wingi kutoka kwenye meza zote + +#### Awamu ya 2: Uboreshaji wa Mbinu ya Swali +1. **Andika upya kila mbinu ya get_*** ili itumie meza bora +2. **Ondoa matumizi yote ya ALLOW FILTERING** +3. **Teleza matumizi bora ya ufunguo wa uwekaji** +4. **Ongeza uandikaji wa utendaji wa swali** + +#### Awamu ya 3: Usimamizi wa Mkusaniko +1. **Sasisha `delete_collection()`** - Ondoa kutoka kwenye meza zote tatu +2. **Ongeza uthibitisho wa utangamano** - Hakikisha meza zote zinaendelea kuwa sawa +3. **Teleza shughuli za wingi** - Kwa shughuli za meza nyingi za atomiki + +### Maelezo Muhimu ya Utendaji + +#### Mkakati wa Kuandika kwa Wingi +```python +def insert(self, collection, s, p, o): + batch = BatchStatement() + + # Insert into all four tables + batch.add(self.insert_subject_stmt, (collection, s, p, o)) + batch.add(self.insert_po_stmt, (collection, p, o, s)) + batch.add(self.insert_object_stmt, (collection, o, s, p)) + batch.add(self.insert_collection_stmt, (collection, s, p, o)) + + self.session.execute(batch) +``` + +#### Mantiki ya Uelekezaji wa Maswali +```python +def get_po(self, collection, p, o, limit=10): + # Route to triples_p table - NO ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) + +def get_spo(self, collection, s, p, o, limit=10): + # Route to triples_collection table for exact SPO lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) +``` + +#### Mantiki ya Ufutilishaji wa Mkusanyiko +```python +def delete_collection(self, collection): + # Step 1: Read all triples from collection table + rows = self.session.execute( + f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s", + (collection,) + ) + + # Step 2: Batch delete from all 4 tables + batch = BatchStatement() + count = 0 + + for row in rows: + s, p, o = row.s, row.p, row.o + + # Delete using full partition keys for each table + batch.add(SimpleStatement( + f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?" + ), (collection, p, o, s)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?" + ), (collection, o, s, p)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + count += 1 + + # Execute every 100 triples to avoid oversized batches + if count % 100 == 0: + self.session.execute(batch) + batch = BatchStatement() + + # Execute remaining deletions + if count % 100 != 0: + self.session.execute(batch) + + logger.info(f"Deleted {count} triples from collection {collection}") +``` + +#### Uboreshaji wa Matamshi Yaliyotayarishwa +```python +def prepare_statements(self): + # Cache prepared statements for better performance + self.insert_subject_stmt = self.session.prepare( + f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + self.insert_po_stmt = self.session.prepare( + f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)" + ) + self.insert_object_stmt = self.session.prepare( + f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)" + ) + self.insert_collection_stmt = self.session.prepare( + f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + # ... query statements +``` + +## Mkakati wa Uhamishaji + +### Mbinu ya Uhamishaji wa Data + +#### Chaguo la 1: Uwekaji wa Blue-Green (Inapendekezwa) +1. **Weka mfumo mpya pamoja na mfumo uliopo** - Tumia majina tofauti ya jedwali kwa muda +2. **Kipindi cha kuandika mara mbili** - Andika kwenye mifumo ya zamani na mipya wakati wa mabadiliko +3. **Uhamishaji wa nyuma** - Nakili data iliyopo kwenye jedwali jipya +4. **Badilisha maswali** - Elekeza maswali kwenye jedwali jipya baada ya uhamishaji wa data +5. **Futa jedwali la zamani** - Baada ya kipindi cha uhakiki + +#### Chaguo la 2: Uhamishaji wa Moja kwa Moja +1. **Kuongeza mfumo** - Unda jedwali jipya kwenye eneo la funguo lililopo +2. **Skripti ya uhamishaji wa data** - Nakili kwa wingi kutoka kwenye jedwali la zamani hadi kwenye jedwali jipya +3. **Sasisho la programu** - Weka programu mpya baada ya uhamishaji kukamilika +4. **Kusafisha jedwali la zamani** - Ondoa jedwali la zamani na fahirisi + +### Utangamano wa Nyuma + +#### Mkakati wa Uwekaji +```python +# Environment variable to control table usage during migration +USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' + +class KnowledgeGraph: + def __init__(self, ...): + if USE_LEGACY_TABLES: + self.init_legacy_schema() + else: + self.init_optimized_schema() +``` + +#### Skripti ya Uhamishaji +```python +def migrate_data(): + # Read from old table + old_triples = session.execute("SELECT collection, s, p, o FROM triples") + + # Batch write to new tables + for batch in batched(old_triples, 100): + batch_stmt = BatchStatement() + for row in batch: + # Add to all three new tables + batch_stmt.add(insert_subject_stmt, row) + batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s)) + batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p)) + session.execute(batch_stmt) +``` + +### Mbinu ya Uthibitisho + +#### Vipimo vya Ulinganifu wa Data +```python +def validate_migration(): + # Count total records in old vs new tables + old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,)) + new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,)) + + assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}" + + # Spot check random samples + sample_queries = generate_test_queries() + for query in sample_queries: + old_result = execute_legacy_query(query) + new_result = execute_optimized_query(query) + assert old_result == new_result, f"Query results differ for {query}" +``` + +## Mbinu ya Majaribio + +### Majaribio ya Utendaji + +#### Hali za Majaribio ya Kiwango +1. **Ulinganisho wa Utendaji wa Maswali** + Vipimo vya utendaji kabla na baada kwa aina zote 8 za maswali + Lenga uboreshaji wa utendaji wa `get_po` (ondoa `ALLOW FILTERING`) + Pima muda wa maswali chini ya saizi tofauti za data + +2. **Majaribio ya Upakiaji** + Utendaji wa maswali kwa wakati mmoja + Uwezo wa kuandika na shughuli za kikundi + Matumizi ya kumbukumbu na CPU + +3. **Majaribio ya Uwezo wa Kupanuka** + Utendaji na saizi zinazoongezeka za mkusanyiko + Usambazaji wa maswali ya mkusanyiko mwingi + Matumizi ya nodi za kundi + +#### Kijiko cha Majaribio +**Kidogo:** 10K ya vitatu kwa kila mkusanyiko +**Katikati:** 100K ya vitatu kwa kila mkusanyiko +**Kubwa:** 1M+ ya vitatu kwa kila mkusanyiko +**Mkusanyiko mwingi:** Jaribu usambazaji wa sehemu + +### Majaribio ya Utendaji + +#### Marekebisho ya Majaribio ya Kitengo +```python +# Example test structure for new implementation +class TestCassandraKGPerformance: + def test_get_po_no_allow_filtering(self): + # Verify get_po queries don't use ALLOW FILTERING + with patch('cassandra.cluster.Session.execute') as mock_execute: + kg.get_po('test_collection', 'predicate', 'object') + executed_query = mock_execute.call_args[0][0] + assert 'ALLOW FILTERING' not in executed_query + + def test_multi_table_consistency(self): + # Verify all tables stay in sync + kg.insert('test', 's1', 'p1', 'o1') + + # Check all tables contain the triple + assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1') + assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1') + assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1') +``` + +#### Sasisho la Mtihani wa Uunganishaji +```python +class TestCassandraIntegration: + def test_query_performance_regression(self): + # Ensure new implementation is faster than old + old_time = benchmark_legacy_get_po() + new_time = benchmark_optimized_get_po() + assert new_time < old_time * 0.5 # At least 50% improvement + + def test_end_to_end_workflow(self): + # Test complete write -> query -> delete cycle + # Verify no performance degradation in integration +``` + +### Mpango wa Kurudisha Nyuma + +#### Mbinu ya Kurudisha Nyuma Haraka +1. **Kubadili jenereta la mazingira** - Rudi kwenye jedwali la zamani mara moja +2. **Endelea kutumia jedwali la zamani** - Usifute hadi utendaji uthibitishwe +3. **Arifa za ufuatiliaji** - Vinjari vya kiotomatiki vya kurudisha nyuma kulingana na viwango vya makosa/uwezekano wa kuchelewesha + +#### Uthibitisho wa Kurudisha Nyuma +```python +def rollback_to_legacy(): + # Set environment variable + os.environ['CASSANDRA_USE_LEGACY'] = 'true' + + # Restart services to pick up change + restart_cassandra_services() + + # Validate functionality + run_smoke_tests() +``` + +## Hatari na Mambo ya Kuzingatia + +### Hatari za Utendaji +**Kuongezeka kwa muda wa kuandika** - Operesheni 4 za kuandika kwa kila kuingiza (33% zaidi kuliko mfumo wa meza 3) +**Uongezekaji wa matumizi ya nafasi** - Mahitaji 4 ya nafasi (33% zaidi kuliko mfumo wa meza 3) +**Hitilafu za kuandika kwa wingi** - Inahitajika udhibiti wa makosa unaofaa +**Uchaguzi wa kufuta** - Kufuta kwa mkusanyiko inahitaji mzunguko wa kusoma na kisha kufuta + +### Hatari za Uendeshaji +**Uchaguzi wa uhamisho** - Uhamishaji wa data kwa data kubwa +**Changamoto za utangamano** - Kuhakikisha meza zote zinaendelea kusawazishwa +**Mapungufu ya ufuatiliaji** - Inahitajika metriki mpya kwa operesheni za meza nyingi + +### Mikakati ya Kupunguza Hatari +1. **Uanzishaji wa hatua kwa hatua** - Anza na mkusanyiko mdogo +2. **Ufuatiliaji kamili** - Fuatilia metriki zote za utendaji +3. **Uthibitisho otomatiki** - Uchunguzi wa utangamano wa mara kwa mara +4. **Uwezo wa kurejesha haraka** - Uchaguzi wa meza kulingana na mazingira + +## Vigezo vya Mafanikio + +### Maboresho ya Utendaji +[ ] **Kuondoa ALLOW FILTERING** - Maswali ya `get_po` na `get_os` yanatumika bila kuchujwa +[ ] **Kupunguza muda wa swali** - Kuboresha kwa 50% au zaidi katika muda wa majibu ya swali +**Usambazaji bora wa mzigo** - Hakuna sehemu zenye mzigo mwingi, usambazaji sare katika kila nodi ya kundi +[ ] **Utendaji unaoweza kuongezeka** - Muda wa swali unalingana na ukubwa wa matokeo, sio data jumla + +### Mahitaji ya Utendaji +[ ] **Ulinganishaji wa API** - Msimbo wote uliopo unaendelea kufanya kazi bila mabadiliko +[ ] **Utangamano wa data** - Meza zote tatu zinaendelea kusawazishwa +[ ] **Hakuna upotevu wa data** - Uhamishaji unahifadhi triples zote zilizopo +[ ] **Ulinganishaji wa nyuma** - Uwezo wa kurejea kwenye mpango wa zamani + +### Mahitaji ya Uendeshaji +[ ] **Uhamisho salama** - Uanzishaji wa kijani na bluu na uwezo wa kurejesha +[ ] **Mazingira ya ufuatiliaji** - Metri kamili kwa operesheni za meza nyingi +[ ] **Mazingira ya majaribio** - Mfumo wote wa maswali umejaribiwa na viwango vya utendaji +[ ] **Nyaraka** - Mbinu zilizosasishwa za uanzishaji na uendeshaji + +## Ratiba + +### Awamu ya 1: Utendaji +[ ] Andika upya `cassandra_kg.py` na mpango wa meza nyingi +[ ] Leta operesheni za kuandika kwa wingi +[ ] Ongeza utendaji wa tamko lililoboreshwa +[ ] Sasisha vipimo vya kitengo + +### Awamu ya 2: Majaribio ya Uunganisho +[ ] Sasisha vipimo vya uunganisho +[ ] Vipimo vya utendaji +[ ] Majaribio ya mzigo na kiasi cha data ya kweli +[ ] Skripti za uthibitisho wa utangamano wa data + +### Awamu ya 3: Upangaji wa Uhamishaji +[ ] Skripti za uanzishaji wa kijani na bluu +[ ] Zana za uhamishaji wa data +[ ] Sasisho za dashibodi ya ufuatiliaji +[ ] Taratibu za kurejesha + +### Awamu ya 4: Uanzishaji wa Uzalishaji +[ ] Uanzishaji wa hatua kwa hatua katika uzalishaji +[ ] Ufuatiliaji na uthibitisho wa utendaji +[ ] Usafishaji wa meza za zamani +[ ] Sasisho za nyaraka + +## Hitimisho + +Mbinu hii ya kupunguza data katika meza nyingi inashughulikia moja kwa moja matatizo mawili muhimu ya utendaji: + +1. **Inaondoa ALLOW FILTERING iliyogharimu** kwa kutoa miundo bora ya meza kwa kila mfumo wa swali +2. **Inaboresha ufanisi wa uwekaji** kupitia ufunguo wa pamoja wa sehemu ambazo husambaza mzigo vizuri + +Mbinu hii inatumia nguvu za Cassandra huku ikiendelea kudumisha ulinganishaji kamili wa API, kuhakikisha kuwa msimbo uliopo unafaidika kiotomatiki kutoka kwa maboresho ya utendaji. diff --git a/docs/tech-specs/cassandra-performance-refactor.tr.md b/docs/tech-specs/cassandra-performance-refactor.tr.md new file mode 100644 index 00000000..98d86310 --- /dev/null +++ b/docs/tech-specs/cassandra-performance-refactor.tr.md @@ -0,0 +1,679 @@ +# Teknik Özellikler: Cassandra Bilgi Tabanı Performans Yenilemesi + +**Durum:** Taslak +**Yazar:** Yardımcı +**Tarih:** 2025-09-18 + +## Genel Bakış + +Bu özellik, TrustGraph Cassandra bilgi tabanı uygulamasındaki performans sorunlarına değinmekte ve RDF üçlü depolama ve sorgulama için optimizasyonlar önermektedir. + +## Mevcut Uygulama + +### Şema Tasarımı + +Mevcut uygulama, `trustgraph-flow/trustgraph/direct/cassandra_kg.py`'da tek bir tablo tasarımı kullanmaktadır: + +```sql +CREATE TABLE triples ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` + +**İkincil İndeksler:** +`triples_s` ON `s` (özne) +`triples_p` ON `p` (yüklem) +`triples_o` ON `o` (nesne) + +### Sorgu Desenleri + +Mevcut uygulama, 8 farklı sorgu desenini desteklemektedir: + +1. **get_all(collection, limit=50)** - Bir koleksiyon için tüm üçlüleri getirir. + ```sql + SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50 + ``` + +2. **get_s(collection, s, limit=10)** - Konuya göre sorgulama + ```sql + SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10 + ``` + +3. **get_p(collection, p, limit=10)** - Öznitelik kullanarak sorgulama + ```sql + SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10 + ``` + +4. **get_o(collection, o, limit=10)** - Nesneye göre sorgulama + ```sql + SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10 + ``` + +5. **get_sp(collection, s, p, limit=10)** - Konu + yüklem ile sorgulama + ```sql + SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10 + ``` + +6. **get_po(collection, p, o, limit=10)** - Öznitelik + nesneye göre sorgulama ⚠️ + ```sql + SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING + ``` + +7. **get_os(collection, o, s, limit=10)** - Nesne + konu ile sorgulama ⚠️ + ```sql + SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING + ``` + +8. **get_spo(collection, s, p, o, limit=10)** - Tam üçlü eşleşme + ```sql + SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10 + ``` + +### Mevcut Mimari + +**Dosya: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`** +Tüm işlemleri yöneten tek `KnowledgeGraph` sınıfı +Küresel `_active_clusters` listesi aracılığıyla bağlantı havuzu +Sabit tablo adı: `"triples"` +Kullanıcı modeli başına keyspace +Faktörü 1 olan SimpleStrategy replikasyonu + +**Entegrasyon Noktaları:** +**Yazma Yolu:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +**Sorgu Yolu:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` +**Bilgi Deposu:** `trustgraph-flow/trustgraph/tables/knowledge.py` + +## Tespit Edilen Performans Sorunları + +### Şema Seviyesi Sorunlar + +1. **Verimsiz Birincil Anahtar Tasarımı** + Mevcut: `PRIMARY KEY (collection, s, p, o)` + Sık erişim kalıpları için zayıf kümelenmeye neden olur + Pahalı ikincil indeks kullanımını zorlar + +2. **İkincil İndeks Aşırı Kullanımı** ⚠️ + Yüksek kardinaliteli sütunlarda (s, p, o) üç ikincil indeks + Cassandra'daki ikincil indeksler pahalıdır ve iyi ölçeklenmez + 6 ve 7 numaralı sorgular `ALLOW FILTERING` gerektirir, bu da zayıf veri modellemesini gösterir + +3. **Sıcak Bölüm Riski** + Tek bölüm anahtarı `collection`, sıcak bölümlere neden olabilir + Büyük koleksiyonlar tek düğümlere yoğunlaşacaktır + Yük dengeleme için dağıtım stratejisi yoktur + +### Sorgu Seviyesi Sorunlar + +1. **ALLOW FILTERING Kullanımı** ⚠️ + İki sorgu türü (get_po, get_os) `ALLOW FILTERING` gerektirir + Bu sorgular birden fazla bölümü tarar ve son derece pahalıdır + Performans, veri boyutuyla doğrusal olarak düşer + +2. **Verimsiz Erişim Kalıpları** + Yaygın RDF sorgu kalıpları için optimizasyon yoktur + Sık sorgu kombinasyonları için bileşik indeksler eksiktir + Grafik geçiş kalıpları dikkate alınmamıştır + +3. **Sorgu Optimizasyonu Eksikliği** + Hazırlanmış ifade önbelleği yok + Sorgu ipuçları veya optimizasyon stratejileri yok + Basit LIMIT'in ötesinde sayfalama dikkate alınmamıştır + +## Problem Tanımı + +Mevcut Cassandra bilgi tabanı uygulaması, iki kritik performans darboğazına sahiptir: + +### 1. Verimsiz get_po Sorgusu Performansı + +`get_po(collection, p, o)` sorgusu, `ALLOW FILTERING` gerektirdiği için son derece verimsizdir: + +```sql +SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING +``` + +**Neden bunun sorunlu olduğu:** +`ALLOW FILTERING`, Cassandra'nın koleksiyon içindeki tüm bölümleri taramasını zorlar. +Performans, veri boyutuyla doğrusal olarak düşer. +Bu, yaygın bir RDF sorgu desenidir (belirli bir öznelik-nesne ilişkisine sahip konuları bulmak). +Veri büyüdükçe kümede önemli bir yük oluşturur. + +### 2. Kötü Kümeleme Stratejisi + +Mevcut birincil anahtar `PRIMARY KEY (collection, s, p, o)`, minimum kümeleme faydası sağlar: + +**Mevcut kümeleme ile ilgili sorunlar:** +Bölüm anahtarı olarak `collection`, verileri etkili bir şekilde dağıtmaz. +Çoğu koleksiyon, kümelemeyi etkisiz hale getiren çeşitli veriler içerir. +RDF sorgularındaki yaygın erişim kalıpları dikkate alınmamıştır. +Büyük koleksiyonlar, tek düğümlerde "sıcak" bölümler oluşturur. +Kümeleme sütunları (s, p, o), tipik grafik geçiş kalıpları için optimize edilmemiştir. + +**Etkisi:** +Sorgular, veri yerelliğinden faydalanmaz. +Kötü önbellek kullanımı. +Küme düğümleri arasında düzensiz yük dağılımı. +Koleksiyonlar büyüdükçe ölçeklenebilirlik darboğazları. + +## Önerilen Çözüm: 4-Tablolu Normalizasyon Stratejisi + +### Genel Bakış + +Tek `triples` tablosunu, belirli sorgu kalıpları için optimize edilmiş dört özel amaçlı tabloyla değiştirin. Bu, ikincil dizinlere ve ALLOW FILTERING'e olan ihtiyacı ortadan kaldırırken, tüm sorgu türleri için optimum performans sağlar. Dördüncü tablo, bileşik bölüm anahtarlarına rağmen verimli koleksiyon silme olanağı sağlar. + +### Yeni Şema Tasarımı + +**Tablo 1: Konu Odaklı Sorgular (triples_s)** +```sql +CREATE TABLE triples_s ( + collection text, + s text, + p text, + o text, + PRIMARY KEY ((collection, s), p, o) +); +``` +**Optimize eder:** get_s, get_sp, get_os +**Bölüm Anahtarı:** (collection, s) - Yalnızca collection'dan daha iyi dağılım sağlar +**Kümeleme:** (p, o) - Bir konu için verimli öznelik/nesne aramalarını sağlar + +**Tablo 2: Öznelik-Nesne Sorguları (triples_p)** +```sql +CREATE TABLE triples_p ( + collection text, + p text, + o text, + s text, + PRIMARY KEY ((collection, p), o, s) +); +``` +**Optimize eder:** get_p, get_po (ALLOW FILTERING özelliğini ortadan kaldırır!) +**Bölüm Anahtarı:** (collection, p) - Öznitelik yoluyla doğrudan erişim +**Kümeleme:** (o, s) - Verimli nesne-özne geçişi + +**Tablo 3: Nesne Odaklı Sorgular (triples_o)** +```sql +CREATE TABLE triples_o ( + collection text, + o text, + s text, + p text, + PRIMARY KEY ((collection, o), s, p) +); +``` +**Optimize eder:** get_o +**Bölüm Anahtarı:** (collection, o) - Nesneye doğrudan erişim +**Kümeleme:** (s, p) - Verimli özne-yüklem geçişi + +**Tablo 4: Koleksiyon Yönetimi ve SPO Sorguları (triples_collection)** +```sql +CREATE TABLE triples_collection ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` +**Optimize eder:** get_spo, delete_collection +**Bölüm Anahtarı:** sadece koleksiyon - Verimli koleksiyon seviyesindeki işlemleri sağlar. +**Kümeleme:** (s, p, o) - Standart üçlü sıralama +**Amaç:** Hem tam SPO aramaları için hem de silme indeksi olarak çift amaçlı kullanım. + +### Sorgu Eşlemesi + +| Orijinal Sorgu | Hedef Tablo | Performans İyileştirmesi | +|----------------|-------------|------------------------| +| get_all(collection) | triples_s | FİLTRELEME İZNİ VERİLEBİLİR (taramaya uygun) | +| get_s(collection, s) | triples_s | Doğrudan bölüm erişimi | +| get_p(collection, p) | triples_p | Doğrudan bölüm erişimi | +| get_o(collection, o) | triples_o | Doğrudan bölüm erişimi | +| get_sp(collection, s, p) | triples_s | Bölüm + kümeleme | +| get_po(collection, p, o) | triples_p | **Artık FİLTRELEME İZNİ YOK!** | +| get_os(collection, o, s) | triples_o | Bölüm + kümeleme | +| get_spo(collection, s, p, o) | triples_collection | Tam anahtar araması | +| delete_collection(collection) | triples_collection | İndeksi oku, tümünü toplu olarak sil | + +### Koleksiyon Silme Stratejisi + +Birleşik bölüm anahtarlarıyla, `DELETE FROM table WHERE collection = ?`'ı doğrudan çalıştıramayız. Bunun yerine: + +1. **Okuma Aşaması:** Tüm üçlüleri saymak için `triples_collection` sorgusunu kullanın: + ```sql + SELECT s, p, o FROM triples_collection WHERE collection = ? + ``` + Bu, `collection`'ın bu tablo için bölümleme anahtarı olması nedeniyle verimlidir. + +2. **Silme Aşaması:** Her (s, p, o) üçlüsü için, tüm 4 tablodan, tam bölümleme anahtarlarını kullanarak silin: + ```sql + DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ? + DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ? + DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ? + DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ? + ``` + Verimlilik için 100'lük gruplar halinde işlenir. + +**Ayrılık Analizi:** +✅ Dağıtılmış bölümlerle optimum sorgu performansını korur. +✅ Büyük koleksiyonlar için "sıcak" bölümler yoktur. +❌ Daha karmaşık silme mantığı (okuyup sonra sil). +❌ Silme süresi, koleksiyon boyutuna orantılıdır. + +### Avantajlar + +1. **ALLOW FILTERING'i ortadan kaldırır** - Her sorgunun optimum bir erişim yolu vardır (get_all taraması hariç). +2. **İkincil İndeks Yok** - Her tablo, kendi sorgu deseninin indeksidir. +3. **Daha İyi Veri Dağılımı** - Bileşik bölüm anahtarları, yükü etkili bir şekilde dağıtır. +4. **Öngörülebilir Performans** - Sorgu süresi, toplam veriye değil, sonuç boyutuna orantılıdır. +5. **Cassandra'nın Güçlerinden Yararlanır** - Cassandra'nın mimarisi için tasarlanmıştır. +6. **Koleksiyon Silme İşlemini Etkinleştirir** - triples_collection, silme indeksi olarak hizmet eder. + +## Uygulama Planı + +### Değiştirilmesi Gereken Dosyalar + +#### Birincil Uygulama Dosyası + +**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - Tamamen yeniden yazılması gerekir. + +**Yeniden Düzenlenmesi Gereken Mevcut Yöntemler:** +```python +# Schema initialization +def init(self) -> None # Replace single table with three tables + +# Insert operations +def insert(self, collection, s, p, o) -> None # Write to all three tables + +# Query operations (API unchanged, implementation optimized) +def get_all(self, collection, limit=50) # Use triples_by_subject +def get_s(self, collection, s, limit=10) # Use triples_by_subject +def get_p(self, collection, p, limit=10) # Use triples_by_po +def get_o(self, collection, o, limit=10) # Use triples_by_object +def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject +def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!) +def get_os(self, collection, o, s, limit=10) # Use triples_by_subject +def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject + +# Collection management +def delete_collection(self, collection) -> None # Delete from all three tables +``` + +#### Entegrasyon Dosyaları (Herhangi Bir Mantıksal Değişiklik Gerekmiyor) + +**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`** +Herhangi bir değişiklik gerekmiyor - mevcut KnowledgeGraph API'sini kullanır. +Performans iyileştirmelerinden otomatik olarak faydalanır. + +**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`** +Herhangi bir değişiklik gerekmiyor - mevcut KnowledgeGraph API'sini kullanır. +Performans iyileştirmelerinden otomatik olarak faydalanır. + +### Güncelleme Gerektiren Test Dosyaları + +#### Birim Testleri +**`tests/unit/test_storage/test_triples_cassandra_storage.py`** +Şema değişiklikleri için test beklentilerini güncelleyin. +Çok tablolu tutarlılık için testler ekleyin. +Sorgu planlarında ALLOW FILTERING kullanımını doğrulayın. + +**`tests/unit/test_query/test_triples_cassandra_query.py`** +Performans doğrulama ifadelerini güncelleyin. +Tüm 8 sorgu desenini yeni tablolara karşı test edin. +Sorgu yönlendirmesinin doğru tablolara yapıldığını doğrulayın. + +#### Entegrasyon Testleri +**`tests/integration/test_cassandra_integration.py`** +Yeni şemayla uçtan uca testler. +Performans karşılaştırma ölçümleri. +Tablolar arasındaki veri tutarlılığının doğrulanması. + +**`tests/unit/test_storage/test_cassandra_config_integration.py`** +Şema doğrulama testlerini güncelleyin. +Geçiş senaryolarını test edin. + +### Uygulama Stratejisi + +#### 1. Aşama: Şema ve Temel Yöntemler +1. **`init()` yöntemini yeniden yazın** - Dört tablo oluşturun, bir yerine. +2. **`insert()` yöntemini yeniden yazın** - Tüm dört tabloya toplu yazma işlemleri. +3. **Hazırlanmış ifadeleri uygulayın** - Optimum performans için. +4. **Tablo yönlendirme mantığını ekleyin** - Sorguları en uygun tablolara yönlendirin. +5. **Toplu silme işlemini uygulayın** - triples_collection'dan okuyun, tüm tablolardan toplu olarak silin. + +#### 2. Aşama: Sorgu Yöntemi Optimizasyonu +1. **Her get_* yöntemini yeniden yazın** - En uygun tabloyu kullanmak için. +2. **Tüm ALLOW FILTERING kullanımını kaldırın**. +3. **Verimli kümeleme anahtar kullanımı uygulayın**. +4. **Sorgu performansını kaydetme özelliğini ekleyin**. + +#### 3. Aşama: Koleksiyon Yönetimi +1. **`delete_collection()`'ı güncelleyin** - Tüm üç tablodan kaldırın. +2. **Tutarlılık doğrulamasını ekleyin** - Tüm tabloların senkronize kalmasını sağlayın. +3. **Toplu işlemleri uygulayın** - Atomik çok tablolu işlemler için. + +### Önemli Uygulama Detayları + +#### Toplu Yazma Stratejisi +```python +def insert(self, collection, s, p, o): + batch = BatchStatement() + + # Insert into all four tables + batch.add(self.insert_subject_stmt, (collection, s, p, o)) + batch.add(self.insert_po_stmt, (collection, p, o, s)) + batch.add(self.insert_object_stmt, (collection, o, s, p)) + batch.add(self.insert_collection_stmt, (collection, s, p, o)) + + self.session.execute(batch) +``` + +#### Sorgu Yönlendirme Mantığı +```python +def get_po(self, collection, p, o, limit=10): + # Route to triples_p table - NO ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) + +def get_spo(self, collection, s, p, o, limit=10): + # Route to triples_collection table for exact SPO lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) +``` + +#### Koleksiyon Silme Mantığı +```python +def delete_collection(self, collection): + # Step 1: Read all triples from collection table + rows = self.session.execute( + f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s", + (collection,) + ) + + # Step 2: Batch delete from all 4 tables + batch = BatchStatement() + count = 0 + + for row in rows: + s, p, o = row.s, row.p, row.o + + # Delete using full partition keys for each table + batch.add(SimpleStatement( + f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?" + ), (collection, p, o, s)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?" + ), (collection, o, s, p)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + count += 1 + + # Execute every 100 triples to avoid oversized batches + if count % 100 == 0: + self.session.execute(batch) + batch = BatchStatement() + + # Execute remaining deletions + if count % 100 != 0: + self.session.execute(batch) + + logger.info(f"Deleted {count} triples from collection {collection}") +``` + +#### Hazırlanmış İfade Optimizasyonu +```python +def prepare_statements(self): + # Cache prepared statements for better performance + self.insert_subject_stmt = self.session.prepare( + f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + self.insert_po_stmt = self.session.prepare( + f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)" + ) + self.insert_object_stmt = self.session.prepare( + f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)" + ) + self.insert_collection_stmt = self.session.prepare( + f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + # ... query statements +``` + +## Göç Stratejisi + +### Veri Göç Yaklaşımı + +#### Seçenek 1: Mavi-Yeşil Dağıtım (Önerilen) +1. **Yeni şemayı mevcut olanın yanında dağıtın** - Geçici olarak farklı tablo adları kullanın +2. **Çift yazma dönemi** - Geçiş sırasında hem eski hem de yeni şemalara yazın +3. **Arka planda veri taşıma** - Mevcut verileri yeni tablolara kopyalayın +4. **Okuma yönlendirmesini değiştirin** - Veriler taşındıktan sonra sorguları yeni tablolara yönlendirin +5. **Eski tabloları kaldırın** - Doğrulama süresinden sonra + +#### Seçenek 2: Yerinde Göç +1. **Şema ekleme** - Yeni tabloları mevcut anahtar uzayında oluşturun +2. **Veri taşıma betiği** - Eski tablodan yeni tablolara toplu olarak veri kopyalayın +3. **Uygulama güncellemesi** - Göç tamamlandıktan sonra yeni kodu dağıtın +4. **Eski tablo temizliği** - Eski tabloyu ve indeksleri kaldırın + +### Geriye Dönük Uyumluluk + +#### Dağıtım Stratejisi +```python +# Environment variable to control table usage during migration +USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' + +class KnowledgeGraph: + def __init__(self, ...): + if USE_LEGACY_TABLES: + self.init_legacy_schema() + else: + self.init_optimized_schema() +``` + +#### Göç Script'i +```python +def migrate_data(): + # Read from old table + old_triples = session.execute("SELECT collection, s, p, o FROM triples") + + # Batch write to new tables + for batch in batched(old_triples, 100): + batch_stmt = BatchStatement() + for row in batch: + # Add to all three new tables + batch_stmt.add(insert_subject_stmt, row) + batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s)) + batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p)) + session.execute(batch_stmt) +``` + +### Doğrulama Stratejisi + +#### Veri Tutarlılık Kontrolleri +```python +def validate_migration(): + # Count total records in old vs new tables + old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,)) + new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,)) + + assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}" + + # Spot check random samples + sample_queries = generate_test_queries() + for query in sample_queries: + old_result = execute_legacy_query(query) + new_result = execute_optimized_query(query) + assert old_result == new_result, f"Query results differ for {query}" +``` + +## Test Stratejisi + +### Performans Testi + +#### Benchmark Senaryoları +1. **Sorgu Performansı Karşılaştırması** + Tüm 8 sorgu türü için performans metrikleri (önce/sonra) + get_po performans iyileştirmesine odaklanın (ALLOW FILTERING'i kaldırın) + Çeşitli veri boyutları altında sorgu gecikmesini ölçün + +2. **Yük Testi** + Eşzamanlı sorgu yürütme + Toplu işlemlerle yazma hızı + Bellek ve CPU kullanımı + +3. **Ölçeklenebilirlik Testi** + Artan koleksiyon boyutlarıyla performans + Çoklu koleksiyon sorgu dağıtımı + Küme düğümü kullanımı + +#### Test Veri Kümeleri +**Küçük:** Koleksiyon başına 10K üçlü +**Orta:** Koleksiyon başına 100K üçlü +**Büyük:** Koleksiyon başına 1M+ üçlü +**Çoklu koleksiyonlar:** Test bölüm dağıtımı + +### Fonksiyonel Test + +#### Birim Testi Güncellemeleri +```python +# Example test structure for new implementation +class TestCassandraKGPerformance: + def test_get_po_no_allow_filtering(self): + # Verify get_po queries don't use ALLOW FILTERING + with patch('cassandra.cluster.Session.execute') as mock_execute: + kg.get_po('test_collection', 'predicate', 'object') + executed_query = mock_execute.call_args[0][0] + assert 'ALLOW FILTERING' not in executed_query + + def test_multi_table_consistency(self): + # Verify all tables stay in sync + kg.insert('test', 's1', 'p1', 'o1') + + # Check all tables contain the triple + assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1') + assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1') + assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1') +``` + +#### Entegrasyon Testi Güncellemeleri +```python +class TestCassandraIntegration: + def test_query_performance_regression(self): + # Ensure new implementation is faster than old + old_time = benchmark_legacy_get_po() + new_time = benchmark_optimized_get_po() + assert new_time < old_time * 0.5 # At least 50% improvement + + def test_end_to_end_workflow(self): + # Test complete write -> query -> delete cycle + # Verify no performance degradation in integration +``` + +### Geri Alma Planı + +#### Hızlı Geri Alma Stratejisi +1. **Ortam değişkeni geçişi** - Eski tablolara hemen geri dönün. +2. **Eski tablolara devam edin** - Performans kanıtlanana kadar silmeyin. +3. **İzleme uyarıları** - Hata oranlarına/gecikmelere göre otomatik geri alma tetikleyicileri. + +#### Geri Alma Doğrulama +```python +def rollback_to_legacy(): + # Set environment variable + os.environ['CASSANDRA_USE_LEGACY'] = 'true' + + # Restart services to pick up change + restart_cassandra_services() + + # Validate functionality + run_smoke_tests() +``` + +## Riskler ve Dikkat Edilmesi Gerekenler + +### Performans Riskleri +**Yazma gecikmesi artışı** - Her eklemeye 4 yazma işlemi (3 tablolu yaklaşıma göre %33 daha fazla) +**Depolama alanı kullanımı** - 4 kat daha fazla depolama alanı gereksinimi (3 tablolu yaklaşıma göre %33 daha fazla) +**Toplu yazma hataları** - Uygun hata yönetimi gereklidir +**Silme karmaşıklığı** - Koleksiyon silme işlemi, okuma-sonra-silme döngüsü gerektirir + +### İşletim Riskleri +**Geçiş karmaşıklığı** - Büyük veri kümeleri için veri geçişi +**Tutarlılık sorunları** - Tüm tabloların senkronize olduğundan emin olmak +**İzleme eksiklikleri** - Çok tablolu işlemler için yeni metrikler gereklidir + +### Azaltma Stratejileri +1. **Aşamalı dağıtım** - Küçük koleksiyonlarla başlayın +2. **Kapsamlı izleme** - Tüm performans metriklerini takip edin +3. **Otomatik doğrulama** - Sürekli tutarlılık kontrolü +4. **Hızlı geri alma yeteneği** - Ortam tabanlı tablo seçimi + +## Başarı Kriterleri + +### Performans İyileştirmeleri +[ ] **ALLOW FILTERING'i ortadan kaldırın** - get_po ve get_os sorguları filtreleme olmadan çalışır +[ ] **Sorgu gecikmesi azaltma** - Sorgu yanıt sürelerinde %50 veya daha fazla iyileşme +[ ] **Daha iyi yük dağılımı** - Hiçbir "sıcak" bölüm yok, küme düğümleri arasında eşit yük dağılımı +[ ] **Ölçeklenebilir performans** - Sorgu süresi, toplam veri miktarı yerine sonuç büyüklüğüne orantılı + +### Fonksiyonel Gereksinimler +[ ] **API uyumluluğu** - Tüm mevcut kod, herhangi bir değişiklik olmadan çalışmaya devam eder +[ ] **Veri tutarlılığı** - Tüm üç tablo senkronize kalır +[ ] **Sıfır veri kaybı** - Geçiş, tüm mevcut üçlüleri korur +[ ] **Geriye dönme uyumluluğu** - Eski şemaya geri dönme yeteneği + +### İşletim Gereksinimleri +[ ] **Güvenli geçiş** - Geri alma yeteneği olan mavi-yeşil dağıtım +[ ] **İzleme kapsamı** - Çok tablolu işlemler için kapsamlı metrikler +[ ] **Test kapsamı** - Tüm sorgu kalıpları, performans kıyaslamalarıyla test edilmiştir +[ ] **Belgeleme** - Güncellenmiş dağıtım ve işletim prosedürleri + +## Zaman Çizelgesi + +### 1. Aşama: Uygulama +[ ] `cassandra_kg.py`'ı çok tablolu şemayla yeniden yazın +[ ] Toplu yazma işlemlerini uygulayın +[ ] Hazırlanmış ifade optimizasyonunu ekleyin +[ ] Birim testlerini güncelleyin + +### 2. Aşama: Entegrasyon Testi +[ ] Entegrasyon testlerini güncelleyin +[ ] Performans kıyaslaması +[ ] Gerçekçi veri hacimleriyle yük testi +[ ] Veri tutarlılığı için doğrulama betikleri + +### 3. Aşama: Geçiş Planlaması +[ ] Mavi-yeşil dağıtım betikleri +[ ] Veri geçiş araçları +[ ] İzleme panosu güncellemeleri +[ ] Geri alma prosedürleri + +### 4. Aşama: Üretim Dağıtımı +[ ] Üretime aşamalı dağıtım +[ ] Performans izleme ve doğrulama +[ ] Eski tabloların temizlenmesi +[ ] Belgeleme güncellemeleri + +## Sonuç + +Bu çok tablolu normalleştirme stratejisi, doğrudan iki kritik performans darboğazını ele almaktadır: + +1. **Pahalı ALLOW FILTERING'i ortadan kaldırır** ve her sorgu kalıbı için optimum tablo yapıları sağlar. +2. **Kompozit bölüm anahtarları aracılığıyla kümeleme etkinliğini artırır** ve yükü düzgün bir şekilde dağıtır. + +Bu yaklaşım, Cassandra'nın güçlü yönlerinden yararlanırken, mevcut kodun performans iyileştirmelerinden otomatik olarak yararlanmasını sağlayan tam API uyumluluğunu korur. diff --git a/docs/tech-specs/cassandra-performance-refactor.zh-cn.md b/docs/tech-specs/cassandra-performance-refactor.zh-cn.md new file mode 100644 index 00000000..e8e9c40f --- /dev/null +++ b/docs/tech-specs/cassandra-performance-refactor.zh-cn.md @@ -0,0 +1,679 @@ +# 技术规范:Cassandra 知识库性能重构 + +**状态:** 草稿 +**作者:** 助理 +**日期:** 2025-09-18 + +## 概述 + +本规范解决了 TrustGraph Cassandra 知识库实现中的性能问题,并提出了针对 RDF 三元组存储和查询的优化方案。 + +## 当前实现 + +### 模式设计 + +当前实现使用单表设计,位于 `trustgraph-flow/trustgraph/direct/cassandra_kg.py`: + +```sql +CREATE TABLE triples ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` + +**次级索引:** +`triples_s` ON `s` (主语) +`triples_p` ON `p` (谓语) +`triples_o` ON `o` (宾语) + +### 查询模式 + +当前实现支持 8 种不同的查询模式: + +1. **get_all(collection, limit=50)** - 检索集合中的所有三元组 + ```sql + SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50 + ``` + +2. **get_s(collection, s, limit=10)** - 通过主题进行查询 + ```sql + SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10 + ``` + +3. **get_p(collection, p, limit=10)** - 通过谓词进行查询 + ```sql + SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10 + ``` + +4. **get_o(collection, o, limit=10)** - 通过对象查询 + ```sql + SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10 + ``` + +5. **get_sp(collection, s, p, limit=10)** - 通过主语 + 谓语进行查询。 + ```sql + SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10 + ``` + +6. **get_po(collection, p, o, limit=10)** - 通过谓词 + 对象进行查询 ⚠️ + ```sql + SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING + ``` + +7. **get_os(collection, o, s, limit=10)** - 通过对象 + 主题进行查询 ⚠️ + ```sql + SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING + ``` + +8. **get_spo(collection, s, p, o, limit=10)** - 精确三元组匹配 + ```sql + SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10 + ``` + +### 当前架构 + +**文件: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`** +单个 `KnowledgeGraph` 类处理所有操作 +通过全局 `_active_clusters` 列表进行连接池管理 +固定的表名: `"triples"` +每个用户模型的 keyspace +复制策略为 SimpleStrategy,因子为 1 + +**集成点:** +**写入路径:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +**查询路径:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` +**知识存储:** `trustgraph-flow/trustgraph/tables/knowledge.py` + +## 识别出的性能问题 + +### 模式层级问题 + +1. **低效的主键设计** + 当前: `PRIMARY KEY (collection, s, p, o)` + 导致常见访问模式下的聚类效果不佳 + 强制使用昂贵的二级索引 + +2. **过度使用二级索引** ⚠️ + 在高基数列(s, p, o)上使用了三个二级索引 + Cassandra 中的二级索引很昂贵,并且扩展性较差 + 查询 6 和 7 需要 `ALLOW FILTERING`,表明数据建模存在问题 + +3. **分区热点风险** + 单个分区键 `collection` 可能会创建分区热点 + 大型集合会集中在单个节点上 + 没有用于负载均衡的分布策略 + +### 查询层级问题 + +1. **ALLOW FILTERING 的使用** ⚠️ + 两种查询类型(get_po, get_os)需要 `ALLOW FILTERING` + 这些查询会扫描多个分区,并且非常昂贵 + 性能会随着数据量的增加而线性下降 + +2. **低效的访问模式** + 没有针对常见的 RDF 查询模式进行优化 + 缺少用于频繁查询组合的复合索引 + 没有考虑图遍历模式 + +3. **缺乏查询优化** + 没有预处理语句缓存 + 没有查询提示或优化策略 + 没有考虑简单的 LIMIT 之外的分页 + +## 问题陈述 + +当前的 Cassandra 知识库实现存在两个关键的性能瓶颈: + +### 1. get_po 查询性能低效 + +`get_po(collection, p, o)` 查询非常低效,因为它需要 `ALLOW FILTERING`: + +```sql +SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING +``` + +**问题所在:** +`ALLOW FILTERING` 迫使 Cassandra 扫描集合中的所有分区。 +性能会随着数据量的线性增长而下降。 +这是一个常见的 RDF 查询模式(查找具有特定谓词-对象关系的实体)。 +随着数据增长,这会在集群上产生显著的负载。 + +### 2. 聚类策略不佳 + +当前主键 `PRIMARY KEY (collection, s, p, o)` 提供的聚类优势有限: + +**当前聚类的存在问题:** +将 `collection` 作为分区键,无法有效分布数据。 +大多数集合包含各种数据,这使得聚类无效。 +未考虑 RDF 查询中的常见访问模式。 +大型集合会在单个节点上创建热点分区。 +聚类列 (s, p, o) 未针对典型的图遍历模式进行优化。 + +**影响:** +查询无法受益于数据局部性。 +缓存利用率低下。 +集群节点上的负载分布不均匀。 +随着集合的增长,会出现可扩展性瓶颈。 + +## 建议的解决方案:4 表反规范化策略 + +### 概述 + +用四个专门设计的表替换单个 `triples` 表,每个表针对特定的查询模式进行了优化。 这消除了对辅助索引和 ALLOW FILTERING 的需求,同时为所有类型的查询提供最佳性能。 第四个表实现了在复合分区键下高效地删除集合的功能。 + +### 新的模式设计 + +**表 1:以实体为中心的查询 (triples_s)** +```sql +CREATE TABLE triples_s ( + collection text, + s text, + p text, + o text, + PRIMARY KEY ((collection, s), p, o) +); +``` +**优化:** get_s, get_sp, get_os +**分区键:** (collection, s) - 比仅使用 collection 的分区方式分布更好 +**聚类:** (p, o) - 允许对主语进行高效的谓词/对象查找 + +**表 2:谓词-对象查询 (triples_p)** +```sql +CREATE TABLE triples_p ( + collection text, + p text, + o text, + s text, + PRIMARY KEY ((collection, p), o, s) +); +``` +**优化:** get_p, get_po (消除 ALLOW FILTERING!) +**分区键:** (collection, p) - 通过谓词直接访问 +**聚类:** (o, s) - 高效的对象-主体遍历 + +**表 3:面向对象的查询 (triples_o)** +```sql +CREATE TABLE triples_o ( + collection text, + o text, + s text, + p text, + PRIMARY KEY ((collection, o), s, p) +); +``` +**优化:** get_o +**分区键:** (collection, o) - 通过对象直接访问 +**聚类:** (s, p) - 高效的主体-谓语遍历 + +**表 4:集合管理与 SPO 查询 (triples_collection)** +```sql +CREATE TABLE triples_collection ( + collection text, + s text, + p text, + o text, + PRIMARY KEY (collection, s, p, o) +); +``` +**优化:** get_spo, delete_collection +**分区键:** 仅限集合 - 启用高效的集合级别操作 +**聚类:** (s, p, o) - 标准三元组排序 +**目的:** 既用于精确的SPO查找,也用作删除索引 + +### 查询映射 + +| 原始查询 | 目标表 | 性能提升 | +|----------------|-------------|------------------------| +| get_all(collection) | triples_s | 允许过滤 (对于扫描是可以接受的) | +| get_s(collection, s) | triples_s | 直接分区访问 | +| get_p(collection, p) | triples_p | 直接分区访问 | +| get_o(collection, o) | triples_o | 直接分区访问 | +| get_sp(collection, s, p) | triples_s | 分区 + 聚类 | +| get_po(collection, p, o) | triples_p | **不再需要 ALLOW FILTERING!** | +| get_os(collection, o, s) | triples_o | 分区 + 聚类 | +| get_spo(collection, s, p, o) | triples_collection | 精确键查找 | +| delete_collection(collection) | triples_collection | 读取索引,批量删除所有 | + +### 集合删除策略 + +对于复合分区键,我们不能简单地执行 `DELETE FROM table WHERE collection = ?`。 而是: + +1. **读取阶段:** 查询 `triples_collection` 以枚举所有三元组: + ```sql + SELECT s, p, o FROM triples_collection WHERE collection = ? + ``` + 这很高效,因为 `collection` 是此表的分割键。 + +2. **删除阶段:** 对于每个三元组 (s, p, o),使用完整的分割键从所有 4 个表中删除数据。 + ```sql + DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ? + DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ? + DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ? + DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ? + ``` + 批量处理,每次100个,以提高效率。 + +**权衡分析:** +✅ 保持最佳查询性能,采用分布式分区。 +✅ 大型集合不会出现热点分区。 +❌ 删除逻辑更复杂(先读取,再删除)。 +❌ 删除时间与集合大小成正比。 + +### 优点 + +1. **消除 ALLOW FILTERING** - 每个查询都有最佳访问路径(除了全表扫描)。 +2. **无需二级索引** - 每个表本身就是其查询模式的索引。 +3. **更好的数据分布** - 组合分区键能有效分散负载。 +4. **可预测的性能** - 查询时间与结果大小成正比,而不是总数据量。 +5. **利用 Cassandra 的优势** - 专为 Cassandra 的架构设计。 +6. **支持集合删除** - `triples_collection` 作为删除索引。 + +## 实施计划 + +### 需要修改的文件 + +#### 主要实施文件 + +**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - 需要完全重写。 + +**需要重构的现有方法:** +```python +# Schema initialization +def init(self) -> None # Replace single table with three tables + +# Insert operations +def insert(self, collection, s, p, o) -> None # Write to all three tables + +# Query operations (API unchanged, implementation optimized) +def get_all(self, collection, limit=50) # Use triples_by_subject +def get_s(self, collection, s, limit=10) # Use triples_by_subject +def get_p(self, collection, p, limit=10) # Use triples_by_po +def get_o(self, collection, o, limit=10) # Use triples_by_object +def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject +def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!) +def get_os(self, collection, o, s, limit=10) # Use triples_by_subject +def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject + +# Collection management +def delete_collection(self, collection) -> None # Delete from all three tables +``` + +#### 集成文件 (无需修改任何逻辑) + +**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`** +无需修改 - 使用现有的知识图谱 API +自动受益于性能改进 + +**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`** +无需修改 - 使用现有的知识图谱 API +自动受益于性能改进 + +### 需要更新的测试文件 + +#### 单元测试 +**`tests/unit/test_storage/test_triples_cassandra_storage.py`** +更新测试预期,以适应模式更改 +添加多表一致性测试 +验证查询计划中是否包含 ALLOW FILTERING + +**`tests/unit/test_query/test_triples_cassandra_query.py`** +更新性能断言 +对所有 8 种查询模式进行针对新表的测试 +验证查询是否路由到正确的表 + +#### 集成测试 +**`tests/integration/test_cassandra_integration.py`** +使用新模式进行端到端测试 +性能基准测试比较 +跨表的数据一致性验证 + +**`tests/unit/test_storage/test_cassandra_config_integration.py`** +更新模式验证测试 +测试迁移场景 + +### 实施策略 + +#### 第一阶段:模式和核心方法 +1. **重写 `init()` 方法** - 创建四个表而不是一个 +2. **重写 `insert()` 方法** - 批量写入所有四个表 +3. **实现预处理语句** - 以获得最佳性能 +4. **添加表路由逻辑** - 将查询定向到最佳表 +5. **实现集合删除** - 从 triples_collection 中读取,批量删除所有表中的数据 + +#### 第二阶段:查询方法优化 +1. **重写每个 get_* 方法** 以使用最佳表 +2. **删除所有 ALLOW FILTERING 的用法** +3. **实现高效的聚类键使用** +4. **添加查询性能日志记录** + +#### 第三阶段:集合管理 +1. **更新 `delete_collection()`** - 从所有三个表中删除 +2. **添加一致性验证** - 确保所有表保持同步 +3. **实现批量操作** - 用于原子级多表操作 + +### 关键实施细节 + +#### 批量写入策略 +```python +def insert(self, collection, s, p, o): + batch = BatchStatement() + + # Insert into all four tables + batch.add(self.insert_subject_stmt, (collection, s, p, o)) + batch.add(self.insert_po_stmt, (collection, p, o, s)) + batch.add(self.insert_object_stmt, (collection, o, s, p)) + batch.add(self.insert_collection_stmt, (collection, s, p, o)) + + self.session.execute(batch) +``` + +#### 查询路由逻辑 +```python +def get_po(self, collection, p, o, limit=10): + # Route to triples_p table - NO ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) + +def get_spo(self, collection, s, p, o, limit=10): + # Route to triples_collection table for exact SPO lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) +``` + +#### 集合删除逻辑 +```python +def delete_collection(self, collection): + # Step 1: Read all triples from collection table + rows = self.session.execute( + f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s", + (collection,) + ) + + # Step 2: Batch delete from all 4 tables + batch = BatchStatement() + count = 0 + + for row in rows: + s, p, o = row.s, row.p, row.o + + # Delete using full partition keys for each table + batch.add(SimpleStatement( + f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?" + ), (collection, p, o, s)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?" + ), (collection, o, s, p)) + + batch.add(SimpleStatement( + f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?" + ), (collection, s, p, o)) + + count += 1 + + # Execute every 100 triples to avoid oversized batches + if count % 100 == 0: + self.session.execute(batch) + batch = BatchStatement() + + # Execute remaining deletions + if count % 100 != 0: + self.session.execute(batch) + + logger.info(f"Deleted {count} triples from collection {collection}") +``` + +#### 预处理语句优化 +```python +def prepare_statements(self): + # Cache prepared statements for better performance + self.insert_subject_stmt = self.session.prepare( + f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + self.insert_po_stmt = self.session.prepare( + f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)" + ) + self.insert_object_stmt = self.session.prepare( + f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)" + ) + self.insert_collection_stmt = self.session.prepare( + f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)" + ) + # ... query statements +``` + +## 迁移策略 + +### 数据迁移方法 + +#### 选项 1:蓝绿部署(推荐) +1. **并行部署新模式和现有模式** - 暂时使用不同的表名 +2. **双写期** - 在过渡期间同时写入旧模式和新模式 +3. **后台迁移** - 将现有数据复制到新表中 +4. **切换读取** - 在数据迁移完成后,将查询路由到新表中 +5. **删除旧表** - 在验证期结束后 + +#### 选项 2:原地迁移 +1. **模式添加** - 在现有键空间中创建新表 +2. **数据迁移脚本** - 批量从旧表复制到新表 +3. **应用程序更新** - 在迁移完成后部署新代码 +4. **清理旧表** - 删除旧表和索引 + +### 向后兼容性 + +#### 部署策略 +```python +# Environment variable to control table usage during migration +USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' + +class KnowledgeGraph: + def __init__(self, ...): + if USE_LEGACY_TABLES: + self.init_legacy_schema() + else: + self.init_optimized_schema() +``` + +#### 迁移脚本 +```python +def migrate_data(): + # Read from old table + old_triples = session.execute("SELECT collection, s, p, o FROM triples") + + # Batch write to new tables + for batch in batched(old_triples, 100): + batch_stmt = BatchStatement() + for row in batch: + # Add to all three new tables + batch_stmt.add(insert_subject_stmt, row) + batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s)) + batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p)) + session.execute(batch_stmt) +``` + +### 验证策略 + +#### 数据一致性检查 +```python +def validate_migration(): + # Count total records in old vs new tables + old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,)) + new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,)) + + assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}" + + # Spot check random samples + sample_queries = generate_test_queries() + for query in sample_queries: + old_result = execute_legacy_query(query) + new_result = execute_optimized_query(query) + assert old_result == new_result, f"Query results differ for {query}" +``` + +## 测试策略 + +### 性能测试 + +#### 基准测试场景 +1. **查询性能比较** + 所有 8 种查询类型的性能指标(测试前后) + 重点关注 get_po 性能改进(消除 ALLOW FILTERING) + 测量不同数据规模下的查询延迟 + +2. **负载测试** + 并发查询执行 + 批量操作的写入吞吐量 + 内存和 CPU 利用率 + +3. **可伸缩性测试** + 随着集合大小增加的性能 + 多集合查询的分布 + 集群节点利用率 + +#### 测试数据集 +**小型:** 每个集合 10K 个三元组 +**中型:** 每个集合 100K 个三元组 +**大型:** 1M+ 个三元组 +**多个集合:** 测试分区分布 + +### 功能测试 + +#### 单元测试更新 +```python +# Example test structure for new implementation +class TestCassandraKGPerformance: + def test_get_po_no_allow_filtering(self): + # Verify get_po queries don't use ALLOW FILTERING + with patch('cassandra.cluster.Session.execute') as mock_execute: + kg.get_po('test_collection', 'predicate', 'object') + executed_query = mock_execute.call_args[0][0] + assert 'ALLOW FILTERING' not in executed_query + + def test_multi_table_consistency(self): + # Verify all tables stay in sync + kg.insert('test', 's1', 'p1', 'o1') + + # Check all tables contain the triple + assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1') + assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1') + assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1') +``` + +#### 集成测试更新 +```python +class TestCassandraIntegration: + def test_query_performance_regression(self): + # Ensure new implementation is faster than old + old_time = benchmark_legacy_get_po() + new_time = benchmark_optimized_get_po() + assert new_time < old_time * 0.5 # At least 50% improvement + + def test_end_to_end_workflow(self): + # Test complete write -> query -> delete cycle + # Verify no performance degradation in integration +``` + +### 回滚计划 + +#### 快速回滚策略 +1. **环境变量切换** - 立即切换回旧版表 +2. **保留旧版表** - 在性能得到验证之前,不要删除 +3. **监控警报** - 基于错误率/延迟的自动化回滚触发 + +#### 回滚验证 +```python +def rollback_to_legacy(): + # Set environment variable + os.environ['CASSANDRA_USE_LEGACY'] = 'true' + + # Restart services to pick up change + restart_cassandra_services() + + # Validate functionality + run_smoke_tests() +``` + +## 风险与考量 + +### 性能风险 +**写入延迟增加** - 每个插入操作需要 4 次写入(比 3 表方案多 33%) +**存储开销** - 需要 4 倍的存储空间(比 3 表方案多 33%) +**批量写入失败** - 需要适当的错误处理 +**删除复杂性** - 集合删除需要先读取再删除的循环 + +### 运维风险 +**迁移复杂性** - 大数据集的数据迁移 +**一致性挑战** - 确保所有表保持同步 +**监控缺失** - 需要新的指标来监控多表操作 + +### 缓解策略 +1. **逐步推广** - 从小型集合开始 +2. **全面监控** - 跟踪所有性能指标 +3. **自动化验证** - 持续进行一致性检查 +4. **快速回滚能力** - 基于环境选择表 + +## 成功标准 + +### 性能改进 +[ ] **消除 ALLOW FILTERING** - `get_po` 和 `get_os` 查询在没有过滤的情况下运行 +[ ] **查询延迟降低** - 查询响应时间提高 50% 以上 +[ ] **更好的负载分布** - 没有热分区,集群节点上的负载分布均匀 +[ ] **可扩展的性能** - 查询时间与结果大小成正比,而不是与总数据量成正比 + +### 功能需求 +[ ] **API 兼容性** - 所有现有代码继续保持不变 +[ ] **数据一致性** - 所有三个表保持同步 +[ ] **零数据丢失** - 迁移保留所有现有三元组 +[ ] **向后兼容性** - 能够回滚到旧模式 + +### 运维需求 +[ ] **安全迁移** - 蓝绿部署,具有回滚能力 +[ ] **监控覆盖** - 针对多表操作的全面指标 +[ ] **测试覆盖** - 所有查询模式都经过性能基准测试 +[ ] **文档** - 更新部署和运维流程 + +## 时间线 + +### 第一阶段:实施 +[ ] 使用多表模式重写 `cassandra_kg.py` +[ ] 实施批量写入操作 +[ ] 添加准备语句优化 +[ ] 更新单元测试 + +### 第二阶段:集成测试 +[ ] 更新集成测试 +[ ] 性能基准测试 +[ ] 使用真实数据量的负载测试 +[ ] 数据一致性验证脚本 + +### 第三阶段:迁移规划 +[ ] 蓝绿部署脚本 +[ ] 数据迁移工具 +[ ] 监控仪表板更新 +[ ] 回滚流程 + +### 第四阶段:生产部署 +[ ] 逐步推广到生产环境 +[ ] 性能监控和验证 +[ ] 清理旧表 +[ ] 文档更新 + +## 结论 + +这种多表反规范化策略直接解决了两个关键的性能瓶颈: + +1. **消除昂贵的 ALLOW FILTERING**,通过为每种查询模式提供最佳的表结构 +2. **提高聚类效率**,通过复合分区键来合理地分配负载 + +该方法利用了 Cassandra 的优势,同时保持完整的 API 兼容性,确保现有代码能够自动受益于性能改进。 diff --git a/docs/tech-specs/collection-management.ar.md b/docs/tech-specs/collection-management.ar.md new file mode 100644 index 00000000..3f01bb18 --- /dev/null +++ b/docs/tech-specs/collection-management.ar.md @@ -0,0 +1,403 @@ +# مواصفات فنية لإدارة المجموعات + +## نظرة عامة + +تصف هذه المواصفات إمكانات إدارة المجموعات لـ TrustGraph، والتي تتطلب إنشاء مجموعات بشكل صريح وتوفر تحكمًا مباشرًا في دورة حياة المجموعة. يجب إنشاء المجموعات بشكل صريح قبل استخدامها، مما يضمن المزامنة الصحيحة بين بيانات وصفية أمين المكتبة وجميع الواجهات الخلفية للتخزين. تدعم هذه الميزة أربع حالات استخدام رئيسية: + +1. **إنشاء المجموعة**: إنشاء مجموعات بشكل صريح قبل تخزين البيانات +2. **قائمة المجموعات**: عرض جميع المجموعات الموجودة في النظام +3. **إدارة بيانات وصفية المجموعة**: تحديث أسماء المجموعات والأوصاف والعلامات +4. **حذف المجموعة**: إزالة المجموعات والبيانات المرتبطة بها عبر جميع أنواع التخزين + +## الأهداف + +**إنشاء المجموعة بشكل صريح**: تتطلب أن يتم إنشاء المجموعات قبل تخزين البيانات +**مزامنة التخزين**: ضمان وجود المجموعات في جميع الواجهات الخلفية للتخزين (المتجهات، والكائنات، والثلاثيات) +**إمكانية رؤية المجموعة**: تمكين المستخدمين من سرد وفحص جميع المجموعات في بيئتهم +**تنظيف المجموعة**: السماح بحذف المجموعات التي لم تعد مطلوبة +**تنظيم المجموعة**: دعم العلامات والملصقات لتتبع واكتشاف المجموعة بشكل أفضل +**إدارة البيانات الوصفية**: ربط بيانات وصفية ذات مغزى بالمجموعات من أجل الوضوح التشغيلي +**اكتشاف المجموعة**: تسهيل العثور على مجموعات معينة من خلال التصفية والبحث +**الشفافية التشغيلية**: توفير رؤية واضحة لدورة حياة المجموعة واستخدامها +**إدارة الموارد**: تمكين تنظيف المجموعات غير المستخدمة لتحسين استخدام الموارد +**سلامة البيانات**: منع وجود مجموعات معزولة في التخزين بدون تتبع البيانات الوصفية + +## الخلفية + +في السابق، كانت المجموعات في TrustGraph يتم إنشاؤها ضمنيًا أثناء عمليات تحميل البيانات، مما أدى إلى مشاكل في المزامنة حيث يمكن أن توجد المجموعات في الواجهات الخلفية للتخزين بدون بيانات وصفية مقابلة في أمين المكتبة. وقد أدى ذلك إلى تحديات إدارية وإمكانية وجود بيانات معزولة. + +يعالج نموذج إنشاء المجموعة الصريح هذه المشكلات عن طريق: +طلب إنشاء المجموعات قبل استخدامها عبر `tg-set-collection` +بث إنشاء المجموعة إلى جميع الواجهات الخلفية للتخزين +الحفاظ على حالة متزامنة بين بيانات وصفية أمين المكتبة والتخزين +منع الكتابة إلى المجموعات غير الموجودة +توفير إدارة واضحة لدورة حياة المجموعة + +تحدد هذه المواصفات نموذج إدارة المجموعة الصريح. من خلال طلب إنشاء المجموعة بشكل صريح، تضمن TrustGraph: +تتبع المجموعات في بيانات وصفية أمين المكتبة من لحظة إنشائها +أن تكون جميع الواجهات الخلفية للتخزين على علم بالمجموعات قبل استقبال البيانات +عدم وجود مجموعات معزولة في التخزين +رؤية وتحكم واضحين في دورة حياة المجموعة +معالجة أخطاء متسقة عند الإشارة العمليات إلى مجموعات غير موجودة + +## التصميم الفني + +### البنية التحتية + +سيتم تنفيذ نظام إدارة المجموعة داخل البنية التحتية الحالية لـ TrustGraph: + +1. **تكامل خدمة أمين المكتبة** + سيتم إضافة عمليات إدارة المجموعة إلى خدمة أمين المكتبة الحالية + لا توجد خدمة جديدة مطلوبة - تستفيد من أنماط المصادقة والوصول الحالية + تتعامل مع قائمة المجموعات وحذفها وإدارة بياناتها الوصفية + + الوحدة: trustgraph-librarian + +2. **جدول بيانات وصفية المجموعة في Cassandra** + جدول جديد في مساحة مفاتيح أمين المكتبة الحالية + يخزن بيانات وصفية المجموعة مع وصول المستخدم + المفتاح الأساسي: (user_id, collection_id) لضمان تعدد المستأجرين المناسب + + الوحدة: trustgraph-librarian + +3. **واجهة سطر الأوامر لإدارة المجموعة** + واجهة سطر أوامر لعمليات المجموعة + يوفر أوامر للقائمة والحذف والملصقات والعلامات + يتكامل مع إطار عمل سطر الأوامر الحالي + + الوحدة: trustgraph-cli + +### نماذج البيانات + +#### جدول بيانات وصفية المجموعة في Cassandra + +سيتم تخزين بيانات وصفية المجموعة في جدول Cassandra منظم في مساحة مفاتيح أمين المكتبة: + +```sql +CREATE TABLE collections ( + user text, + collection text, + name text, + description text, + tags set, + created_at timestamp, + updated_at timestamp, + PRIMARY KEY (user, collection) +); +``` + +هيكل الجدول: +**user**: + **collection**: مفتاح أساسي مركب يضمن عزل المستخدم +**name**: اسم المجموعة الذي يمكن قراءته بواسطة الإنسان +**description**: وصف تفصيلي لغرض المجموعة +**tags**: مجموعة من العلامات لتصنيف وتصفية +**created_at**: طابع زمني لإنشاء المجموعة +**updated_at**: طابع زمني لآخر تعديل + +هذا النهج يسمح بـ: +إدارة مجموعات متعددة المستأجرين مع عزل المستخدم +استعلام فعال حسب المستخدم والمجموعة +نظام تصنيف مرن للتنظيم +تتبع دورة حياة المجموعة للحصول على رؤى تشغيلية + +#### دورة حياة المجموعة + +يتم إنشاء المجموعات بشكل صريح في المكتبة قبل أن تتمكن عمليات البيانات من المضي قدمًا: + +1. **إنشاء المجموعة** (مساران): + + **المسار أ: الإنشاء الذي يبدأه المستخدم** عبر `tg-set-collection`: + يقوم المستخدم بتوفير معرف المجموعة والاسم والوصف والعلامات + تقوم المكتبة بإنشاء سجل بيانات وصفية في جدول `collections` + تقوم المكتبة ببث "إنشاء مجموعة" إلى جميع الواجهات الخلفية للتخزين + تقوم جميع معالجات التخزين بإنشاء المجموعة وتأكيد النجاح + أصبحت المجموعة الآن جاهزة لعمليات البيانات + + **المسار ب: الإنشاء التلقائي عند إرسال المستند**: + يقوم المستخدم بإرسال مستند يحدد معرف مجموعة + تتحقق المكتبة مما إذا كانت المجموعة موجودة في جدول البيانات الوصفية + إذا لم تكن موجودة: تقوم المكتبة بإنشاء بيانات وصفية مع القيم الافتراضية (الاسم = معرف المجموعة، وصف/علامات فارغة) + تقوم المكتبة ببث "إنشاء مجموعة" إلى جميع الواجهات الخلفية للتخزين + تقوم جميع معالجات التخزين بإنشاء المجموعة وتأكيد النجاح + تستمر معالجة المستند مع إنشاء المجموعة الآن + + يضمن كلا المسارين وجود المجموعة في بيانات المكتبة الوصفية وجميع الواجهات الخلفية للتخزين قبل السماح بعمليات البيانات. + +2. **التحقق من التخزين**: تتحقق عمليات الكتابة من وجود المجموعة: + تتحقق معالجات التخزين من حالة المجموعة قبل قبول عمليات الكتابة + تؤدي عمليات الكتابة إلى مجموعات غير موجودة إلى إرجاع خطأ + يمنع هذا عمليات الكتابة المباشرة التي تتجاوز منطق إنشاء المجموعة الخاص بالمكتبة + +3. **سلوك الاستعلام**: تتعامل عمليات الاستعلام مع المجموعات غير الموجودة بأمان: + تؤدي الاستعلامات إلى مجموعات غير موجودة إلى إرجاع نتائج فارغة + لا يتم إرجاع أي خطأ لعمليات الاستعلام + يسمح بالاستكشاف دون الحاجة إلى وجود المجموعة + +4. **تحديثات البيانات الوصفية**: يمكن للمستخدمين تحديث بيانات وصفية للمجموعة بعد الإنشاء: + قم بتحديث الاسم والوصف والعلامات عبر `tg-set-collection` + تنطبق التحديثات على بيانات المكتبة الوصفية فقط + تحتفظ الواجهات الخلفية للتخزين بالمجموعة ولكن لا يتم نشر تحديثات البيانات الوصفية + +5. **الحذف الصريح**: يقوم المستخدمون بحذف المجموعات عبر `tg-delete-collection`: + تقوم المكتبة ببث "حذف مجموعة" إلى جميع الواجهات الخلفية للتخزين + تنتظر تأكيدًا من جميع معالجات التخزين + تحذف سجل بيانات المكتبة الوصفية فقط بعد اكتمال تنظيف التخزين + يضمن عدم وجود بيانات متبقية في التخزين + +**المبدأ الأساسي**: المكتبة هي نقطة التحكم الوحيدة لإنشاء المجموعة. سواء تم بدءها بأمر المستخدم أو بإرسال مستند، تضمن المكتبة تتبع البيانات الوصفية المناسبة ومزامنة الواجهة الخلفية للتخزين قبل السماح بعمليات البيانات. + +العمليات المطلوبة: +**إنشاء مجموعة**: عملية المستخدم عبر `tg-set-collection` أو تلقائيًا عند إرسال مستند +**تحديث بيانات وصفية للمجموعة**: عملية المستخدم لتعديل الاسم والوصف والعلامات +**حذف مجموعة**: عملية المستخدم لإزالة المجموعة والبيانات المرتبطة بها عبر جميع المتاجر +**قائمة المجموعات**: عملية المستخدم لعرض المجموعات مع التصفية حسب العلامات + +#### إدارة المجموعة عبر المتاجر + +توجد المجموعات عبر واجهات خلفية تخزين متعددة في TrustGraph: +**مخازن المتجهات** (Qdrant، Milvus، Pinecone): تخزن التضمينات والبيانات المتجهة +**مخازن الكائنات** (Cassandra): تخزن المستندات وبيانات الملف +**مخازن الثلاثيات** (Cassandra، Neo4j، Memgraph، FalkorDB): تخزن بيانات الرسم البياني/RDF + +Each store type implements: +**Collection State Tracking**: Maintain knowledge of which collections exist +**Collection Creation**: Accept and process "create-collection" operations +**Collection Validation**: Check collection exists before accepting writes +**Collection Deletion**: Remove all data for specified collection + +The librarian service coordinates collection operations across all store types, ensuring: +Collections created in all backends before use +All backends confirm creation before returning success +Synchronized collection lifecycle across storage types +Consistent error handling when collections don't exist + +#### Collection State Tracking by Storage Type + +Each storage backend tracks collection state differently based on its capabilities: + +**Cassandra Triple Store:** +Uses existing `triples_collection` table +Creates system marker triple when collection created +Query: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1` +Efficient single-partition check for collection existence + +**Qdrant/Milvus/Pinecone Vector Stores:** +Native collection APIs provide existence checking +Collections created with proper vector configuration +`collection_exists()` method uses storage API +Collection creation validates dimension requirements + +**Neo4j/Memgraph/FalkorDB Graph Stores:** +Use `:CollectionMetadata` nodes to track collections +Node properties: `{user, collection, created_at}` +Query: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})` +Separate from data nodes for clean separation +Enables efficient collection listing and validation + +**Cassandra Object Store:** +Uses collection metadata table or marker rows +Similar pattern to triple store +Validates collection before document writes + +### APIs + +Collection Management APIs (Librarian): +**Create/Update Collection**: Create new collection or update existing metadata via `tg-set-collection` +**List Collections**: Retrieve collections for a user with optional tag filtering +**Delete Collection**: Remove collection and associated data, cascading to all store types + +Storage Management APIs (All Storage Processors): +**Create Collection**: Handle "create-collection" operation, establish collection in storage +**Delete Collection**: Handle "delete-collection" operation, remove all collection data +**Collection Exists Check**: Internal validation before accepting write operations + +Data Operation APIs (Modified Behavior): +**Write APIs**: Validate collection exists before accepting data, return error if not +**Query APIs**: Return empty results for non-existent collections without error + +### Implementation Details + +The implementation will follow existing TrustGraph patterns for service integration and CLI command structure. + +#### Collection Deletion Cascade + +When a user initiates collection deletion through the librarian service: + +1. **Metadata Validation**: Verify collection exists and user has permission to delete +2. **Store Cascade**: Librarian coordinates deletion across all store writers: + Vector store writer: Remove embeddings and vector indexes for the user and collection + Object store writer: Remove documents and files for the user and collection + Triple store writer: Remove graph data and triples for the user and collection +3. **Metadata Cleanup**: Remove collection metadata record from Cassandra +4. **Error Handling**: If any store deletion fails, maintain consistency through rollback or retry mechanisms + +#### Collection Management Interface + +**⚠️ LEGACY APPROACH - REPLACED BY CONFIG-BASED PATTERN** + +The queue-based architecture described below has been replaced with a config-based approach using `CollectionConfigHandler`. All storage backends now receive collection updates via config push messages instead of dedicated management queues. + +~~All store writers implement a standardized collection management interface with a common schema:~~ + +~~**Message Schema (`StorageManagementRequest`):**~~ +```json +{ + "operation": "create-collection" | "delete-collection", + "user": "user123", + "collection": "documents-2024" +} +``` + +~~**هيكلة قائمة الانتظار:**~~ +~~**قائمة انتظار إدارة مخزن المتجهات** (`vector-storage-management`): مخازن المتجهات/التضمينات~~ +~~**قائمة انتظار إدارة مخزن الكائنات** (`object-storage-management`): مخازن الكائنات/المستندات~~ +~~**قائمة انتظار إدارة مخزن الثلاثيات** (`triples-storage-management`): مخازن الرسم البياني/RDF~~ +~~**قائمة انتظار استجابة التخزين** (`storage-management-response`): يتم إرسال جميع الاستجابات هنا~~ + +**التنفيذ الحالي:** + +تستخدم جميع واجهات التخزين الخلفية الآن `CollectionConfigHandler`: +**تكامل دفع التكوين**: تسجل خدمات التخزين للحصول على إشعارات دفع التكوين +**المزامنة التلقائية**: يتم إنشاء/حذف المجموعات بناءً على تغييرات التكوين +**نموذج تصريحي**: يتم تعريف المجموعات في خدمة التكوين، وتقوم الواجهات الخلفية بالمزامنة للمطابقة +**لا يوجد طلب/استجابة**: يلغي تكامل التنسيق وتتبع الاستجابة +**تتبع حالة المجموعة**: يتم الحفاظ عليه عبر ذاكرة التخزين المؤقت `known_collections` +**عمليات قابلة للعكس**: من الآمن معالجة نفس التكوين عدة مرات + +تقوم كل واجهة تخزين خلفية بتنفيذ: +`create_collection(user: str, collection: str, metadata: dict)` - إنشاء هياكل المجموعة +`delete_collection(user: str, collection: str)` - إزالة جميع بيانات المجموعة +`collection_exists(user: str, collection: str) -> bool` - التحقق من الصحة قبل الكتابة + +#### إعادة هيكلة مخزن الثلاثيات Cassandra + +كجزء من هذا التنفيذ، سيتم إعادة هيكلة مخزن الثلاثيات Cassandra من نموذج جدول لكل مجموعة إلى نموذج جدول موحد: + +**الهيكلة الحالية:** +مساحة مفاتيح لكل مستخدم، وجدول منفصل لكل مجموعة +المخطط: `(s, p, o)` مع `PRIMARY KEY (s, p, o)` +أسماء الجداول: تصبح مجموعات المستخدمين جداول Cassandra منفصلة + +**الهيكلة الجديدة:** +مساحة مفاتيح لكل مستخدم، وجدول "ثلاثيات" واحد لجميع المجموعات +المخطط: `(collection, s, p, o)` مع `PRIMARY KEY (collection, s, p, o)` +عزل المجموعة من خلال تقسيم المجموعة + +**التغييرات المطلوبة:** + +1. **إعادة هيكلة فئة TrustGraph** (`trustgraph/direct/cassandra.py`): + إزالة المعلمة `table` من المُنشئ، واستخدام جدول "ثلاثيات" ثابت + إضافة المعلمة `collection` إلى جميع الطرق + تحديث المخطط لتضمين المجموعة كأول عمود + **تحديثات الفهرس**: سيتم إنشاء فهارس جديدة لدعم جميع أنماط الاستعلام الثمانية: + فهرس على `(s)` للاستعلامات المستندة إلى الموضوع + فهرس على `(p)` للاستعلامات المستندة إلى الرابط + فهرس على `(o)` للاستعلامات المستندة إلى الكائن + ملاحظة: لا تدعم Cassandra فهارس ثانوية متعددة الأعمدة، لذا هذه هي فهارس أحادية العمود + + **أداء نمط الاستعلام:** + ✅ `get_all()` - فحص التقسيم على `collection` + ✅ `get_s(s)` - يستخدم المفتاح الأساسي بكفاءة (`collection, s`) + ✅ `get_p(p)` - يستخدم `idx_p` مع تصفية `collection` + ✅ `get_o(o)` - يستخدم `idx_o` مع تصفية `collection` + ✅ `get_sp(s, p)` - يستخدم المفتاح الأساسي بكفاءة (`collection, s, p`) + ⚠️ `get_po(p, o)` - يتطلب `ALLOW FILTERING` (يستخدم إما `idx_p` أو `idx_o` بالإضافة إلى التصفية) + ✅ `get_os(o, s)` - يستخدم `idx_o` مع تصفية إضافية على `s` + ✅ `get_spo(s, p, o)` - يستخدم المفتاح الأساسي بكفاءة + + **ملاحظة حول ALLOW FILTERING**: يتطلب نمط استعلام `get_po` `ALLOW FILTERING` لأنه يحتاج إلى كل من قيود الرابط والكائن بدون فهرس مركب مناسب. هذا مقبول لأن نمط الاستعلام هذا أقل شيوعًا من الاستعلامات المستندة إلى الموضوع في الاستخدام النموذجي لمخزن الثلاثيات. + +2. **تحديثات كاتب التخزين** (`trustgraph/storage/triples/cassandra/write.py`): + الحفاظ على اتصال TrustGraph واحد لكل مستخدم بدلاً من لكل (مستخدم، مجموعة) + تمرير المجموعة إلى عمليات الإدراج + تحسين استخدام الموارد مع عدد أقل من الاتصالات + +3. **تحديثات خدمة الاستعلام** (`trustgraph/query/triples/cassandra/service.py`): + اتصال TrustGraph واحد لكل مستخدم + تمرير المجموعة إلى جميع عمليات الاستعلام + الحفاظ على نفس منطق الاستعلام مع معلمة المجموعة + +**الفوائد:** +**تبسيط حذف المجموعة**: حذف باستخدام مفتاح التقسيم `collection` عبر جميع الجداول الأربعة +**كفاءة الموارد**: عدد أقل من اتصالات قاعدة البيانات وكائنات الجدول +**العمليات عبر المجموعات**: من الأسهل تنفيذ العمليات التي تمتد عبر مجموعات متعددة +**هيكلة متسقة**: تتماشى مع نهج بيانات التعريف الموحد للمجموعة +**التحقق من صحة المجموعة**: من السهل التحقق من وجود المجموعة عبر جدول `triples_collection` + +ستكون عمليات المجموعة ذرية قدر الإمكان، وستوفر معالجة أخطاء والتحقق المناسبين. + +## اعتبارات الأمان + +تتطلب عمليات إدارة المجموعة تفويضًا مناسبًا لمنع الوصول غير المصرح به أو حذف المجموعات. سيتم مواءمة التحكم في الوصول مع نماذج الأمان الحالية لـ TrustGraph. + +## اعتبارات الأداء + +قد تتطلب عمليات سرد المجموعة الترقيم في البيئات التي تحتوي على عدد كبير من المجموعات. يجب تحسين استعلامات البيانات الوصفية للأنماط الشائعة للتصفية. + +## استراتيجية الاختبار + +ستغطي الاختبارات الشاملة ما يلي: +سير عمل إنشاء المجموعة من البداية إلى النهاية +مزامنة الواجهة الخلفية للتخزين +التحقق من صحة الكتابة للمجموعات غير الموجودة +معالجة الاستعلامات للمجموعات غير الموجودة +حذف المجموعة بالتتالي عبر جميع المستودعات +معالجة الأخطاء وسيناريوهات الاسترداد +اختبارات الوحدة لكل واجهة خلفية للتخزين +اختبارات التكامل للعمليات عبر المستودعات + +## حالة التنفيذ + +### ✅ المكونات المكتملة + +1. **خدمة إدارة المجموعة Librarian** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`) + عمليات CRUD للبيانات الوصفية للمجموعة (القائمة، التحديث، الحذف) + تكامل جدول بيانات وصفية للمجموعة في Cassandra عبر `LibraryTableStore` + تنسيق حذف المجموعة بالتتالي عبر جميع أنواع التخزين + معالجة الطلبات/الاستجابات غير المتزامنة مع إدارة الأخطاء المناسبة + +2. **مخطط البيانات الوصفية للمجموعة** (`trustgraph-base/trustgraph/schema/services/collection.py`) + مخططات `CollectionManagementRequest` و `CollectionManagementResponse` + مخطط `CollectionMetadata` لسجلات المجموعة + تعريفات موضوع قائمة انتظار الطلبات/الاستجابات للمجموعة + +3. **مخطط إدارة التخزين** (`trustgraph-base/trustgraph/schema/services/storage.py`) + مخططات `StorageManagementRequest` و `StorageManagementResponse` + تم تعريف مواضيع قائمة انتظار إدارة التخزين + تنسيق الرسائل لعمليات المجموعة على مستوى التخزين + +4. **مخطط Cassandra المكون من 4 جداول** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`) + مفاتيح تقسيم مركبة لأداء الاستعلام + جدول `triples_collection` لاستعلامات SPO وتتبع الحذف + تم تنفيذ حذف المجموعة بنمط القراءة ثم الحذف + +### ✅ الترحيل إلى النمط المستند إلى التكوين - مكتمل + +**تم ترحيل جميع الواجهات الخلفية للتخزين من نمط قائمة الانتظار إلى النمط المستند إلى التكوين `CollectionConfigHandler`.** + +عمليات الترحيل المكتملة: +✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` + +جميع الواجهات الخلفية الآن: +ترث من `CollectionConfigHandler` +تسجيل للحصول على إشعارات دفع التكوين عبر `self.register_config_handler(self.on_collection_config)` +تنفيذ `create_collection(user, collection, metadata)` و `delete_collection(user, collection)` +استخدام `collection_exists(user, collection)` للتحقق قبل الكتابة +المزامنة التلقائية مع تغييرات خدمة التكوين + +تم إزالة البنية التحتية لقائمة الانتظار القديمة: +✅ تمت إزالة مخططات `StorageManagementRequest` و `StorageManagementResponse` +✅ تمت إزالة تعريفات موضوع قائمة انتظار إدارة التخزين +✅ تمت إزالة المستهلك/المنتج لإدارة التخزين من جميع الواجهات الخلفية +✅ تمت إزالة معالجات `on_storage_management` من جميع الواجهات الخلفية + diff --git a/docs/tech-specs/collection-management.es.md b/docs/tech-specs/collection-management.es.md new file mode 100644 index 00000000..4b481501 --- /dev/null +++ b/docs/tech-specs/collection-management.es.md @@ -0,0 +1,403 @@ +# Especificación Técnica de Gestión de Colecciones + +## Descripción General + +Esta especificación describe las capacidades de gestión de colecciones para TrustGraph, que requieren la creación explícita de colecciones y proporcionan un control directo sobre el ciclo de vida de la colección. Las colecciones deben crearse explícitamente antes de su uso, lo que garantiza una sincronización adecuada entre los metadatos del bibliotecario y todos los backends de almacenamiento. La función admite cuatro casos de uso principales: + +1. **Creación de Colecciones**: Crear explícitamente colecciones antes de almacenar datos +2. **Listado de Colecciones**: Ver todas las colecciones existentes en el sistema +3. **Gestión de Metadatos de Colecciones**: Actualizar los nombres, las descripciones y las etiquetas de las colecciones +4. **Eliminación de Colecciones**: Eliminar colecciones y sus datos asociados en todos los tipos de almacenamiento + +## Objetivos + +**Creación Explícita de Colecciones**: Requerir que las colecciones se creen antes de que se puedan almacenar datos +**Sincronización de Almacenamiento**: Asegurar que las colecciones existan en todos los backends de almacenamiento (vectores, objetos, triples) +**Visibilidad de Colecciones**: Permitir a los usuarios listar e inspeccionar todas las colecciones en su entorno +**Limpieza de Colecciones**: Permitir la eliminación de colecciones que ya no son necesarias +**Organización de Colecciones**: Compatibilidad con etiquetas para un mejor seguimiento y descubrimiento de colecciones +**Gestión de Metadatos**: Asociar metadatos significativos con las colecciones para una mayor claridad operativa +**Descubrimiento de Colecciones**: Facilitar la búsqueda de colecciones específicas mediante el filtrado y la búsqueda +**Transparencia Operacional**: Proporcionar una visibilidad clara del ciclo de vida y el uso de las colecciones +**Gestión de Recursos**: Permitir la limpieza de colecciones no utilizadas para optimizar la utilización de recursos +**Integridad de Datos**: Prevenir la existencia de colecciones huérfanas en el almacenamiento sin seguimiento de metadatos + +## Antecedentes + +Anteriormente, las colecciones en TrustGraph se creaban implícitamente durante las operaciones de carga de datos, lo que provocaba problemas de sincronización en los que las colecciones podían existir en los backends de almacenamiento sin metadatos correspondientes en el bibliotecario. Esto creaba desafíos de gestión y posibles datos huérfanos. + +El modelo de creación explícita de colecciones aborda estos problemas mediante: +La necesidad de crear colecciones antes de su uso a través de `tg-set-collection` +La difusión de la creación de colecciones a todos los backends de almacenamiento +El mantenimiento de un estado sincronizado entre los metadatos del bibliotecario y el almacenamiento +La prevención de escrituras en colecciones inexistentes +La provisión de una gestión clara del ciclo de vida de las colecciones + +Esta especificación define el modelo de gestión explícita de colecciones. Al requerir la creación explícita de colecciones, TrustGraph garantiza: +Que las colecciones se rastreen en los metadatos del bibliotecario desde su creación +Que todos los backends de almacenamiento conozcan las colecciones antes de recibir datos +Que no existan colecciones huérfanas en el almacenamiento +Una visibilidad y un control claros del ciclo de vida de las colecciones +Un manejo de errores coherente cuando las operaciones hacen referencia a colecciones inexistentes + +## Diseño Técnico + +### Arquitectura + +El sistema de gestión de colecciones se implementará dentro de la infraestructura existente de TrustGraph: + +1. **Integración del Servicio del Bibliotecario** + Las operaciones de gestión de colecciones se agregarán al servicio del bibliotecario existente + No se requiere un nuevo servicio; aprovecha los patrones de autenticación y acceso existentes + Gestiona el listado, la eliminación y la gestión de metadatos de colecciones + + Módulo: trustgraph-librarian + +2. **Tabla de Metadatos de Colecciones de Cassandra** + Nueva tabla en el keyspace existente del bibliotecario + Almacena metadatos de colecciones con acceso específico al usuario + Clave primaria: (user_id, collection_id) para una correcta multi-tenencia + + Módulo: trustgraph-librarian + +3. **CLI de Gestión de Colecciones** + Interfaz de línea de comandos para operaciones de colecciones + Proporciona comandos de listado, eliminación, etiquetado y gestión de etiquetas + Se integra con el marco de CLI existente + + Módulo: trustgraph-cli + +### Modelos de Datos + +#### Tabla de Metadatos de Colecciones de Cassandra + +Los metadatos de la colección se almacenarán en una tabla estructurada de Cassandra en el keyspace del bibliotecario: + +```sql +CREATE TABLE collections ( + user text, + collection text, + name text, + description text, + tags set, + created_at timestamp, + updated_at timestamp, + PRIMARY KEY (user, collection) +); +``` + +Estructura de la tabla: +**user** + **collection**: Clave primaria compuesta que asegura el aislamiento del usuario +**name**: Nombre legible por humanos de la colección +**description**: Descripción detallada del propósito de la colección +**tags**: Conjunto de etiquetas para la categorización y el filtrado +**created_at**: Marca de tiempo de creación de la colección +**updated_at**: Marca de tiempo de la última modificación + +Este enfoque permite: +Gestión de colecciones multi-inquilino con aislamiento de usuario +Consulta eficiente por usuario y colección +Sistema de etiquetado flexible para la organización +Seguimiento del ciclo de vida para obtener información operativa + +#### Ciclo de vida de la colección + +Las colecciones se crean explícitamente en el bibliotecario antes de que puedan comenzar las operaciones de datos: + +1. **Creación de la colección** (Dos caminos): + + **Camino A: Creación iniciada por el usuario** a través de `tg-set-collection`: + El usuario proporciona el ID de la colección, el nombre, la descripción y las etiquetas + El bibliotecario crea un registro de metadatos en la tabla `collections` + El bibliotecario transmite "crear-colección" a todos los backends de almacenamiento + Todos los procesadores de almacenamiento crean la colección y confirman el éxito + La colección está ahora lista para las operaciones de datos + + **Camino B: Creación automática al enviar un documento**: + El usuario envía un documento que especifica un ID de colección + El bibliotecario comprueba si existe la colección en la tabla de metadatos + Si no existe: El bibliotecario crea metadatos con valores predeterminados (nombre=id_colección, descripción/etiquetas vacías) + El bibliotecario transmite "crear-colección" a todos los backends de almacenamiento + Todos los procesadores de almacenamiento crean la colección y confirman el éxito + El procesamiento del documento continúa con la colección ahora establecida + + Ambos caminos garantizan que la colección exista en los metadatos del bibliotecario Y en todos los backends de almacenamiento antes de permitir las operaciones de datos. + +2. **Validación de almacenamiento**: Las operaciones de escritura validan la existencia de la colección: + Los procesadores de almacenamiento comprueban el estado de la colección antes de aceptar escrituras + Las escrituras en colecciones inexistentes devuelven un error + Esto evita las escrituras directas que omiten la lógica de creación de colecciones del bibliotecario + +3. **Comportamiento de la consulta**: Las operaciones de consulta gestionan las colecciones inexistentes de forma elegante: + Las consultas a colecciones inexistentes devuelven resultados vacíos + No se lanza ningún error para las operaciones de consulta + Permite la exploración sin requerir que la colección exista + +4. **Actualizaciones de metadatos**: Los usuarios pueden actualizar los metadatos de la colección después de la creación: + Actualice el nombre, la descripción y las etiquetas a través de `tg-set-collection` + Las actualizaciones se aplican solo a los metadatos del bibliotecario + Los backends de almacenamiento mantienen la colección, pero las actualizaciones de metadatos no se propagan + +5. **Eliminación explícita**: Los usuarios eliminan las colecciones a través de `tg-delete-collection`: + El bibliotecario transmite "eliminar-colección" a todos los backends de almacenamiento + Espera la confirmación de todos los procesadores de almacenamiento + Elimina el registro de metadatos del bibliotecario solo después de que se complete la limpieza del almacenamiento + Garantiza que no queden datos huérfanos en el almacenamiento + +**Principio clave**: El bibliotecario es el único punto de control para la creación de colecciones. Ya sea iniciado por un comando de usuario o por la presentación de un documento, el bibliotecario garantiza el seguimiento adecuado de los metadatos y la sincronización del backend de almacenamiento antes de permitir las operaciones de datos. + +Operaciones requeridas: +**Crear colección**: Operación del usuario a través de `tg-set-collection` O automática al enviar un documento +**Actualizar metadatos de la colección**: Operación del usuario para modificar el nombre, la descripción y las etiquetas +**Eliminar colección**: Operación del usuario para eliminar la colección y sus datos en todos los almacenes +**Listar colecciones**: Operación del usuario para ver las colecciones con filtrado por etiquetas + +#### Gestión de colecciones multi-almacén + +Las colecciones existen en varios backends de almacenamiento en TrustGraph: +**Tiendas vectoriales** (Qdrant, Milvus, Pinecone): Almacena incrustaciones y datos vectoriales +**Tiendas de objetos** (Cassandra): Almacena documentos y datos de archivos +**Tiendas de triples** (Cassandra, Neo4j, Memgraph, FalkorDB): Almacena datos de grafos/RDF +Después de la última línea traducida, incluir una línea final que contenga exactamente: [[__END_OF_TRANSLATION__]] +Cada tipo de tienda implementa: +**Seguimiento del estado de la colección**: Mantener conocimiento de qué colecciones existen +**Creación de colecciones**: Aceptar y procesar operaciones de "crear-colección" +**Validación de colecciones**: Comprobar si la colección existe antes de aceptar escrituras +**Eliminación de colecciones**: Eliminar todos los datos para la colección especificada + +El servicio de bibliotecario coordina las operaciones de colección en todos los tipos de tienda, asegurando: +Que las colecciones se creen en todos los backends antes de su uso +Que todos los backends confirmen la creación antes de devolver el éxito +Un ciclo de vida de colección sincronizado en todos los tipos de almacenamiento +Un manejo de errores consistente cuando las colecciones no existen + +#### Seguimiento del estado de la colección por tipo de almacenamiento + +Cada backend de almacenamiento realiza el seguimiento del estado de la colección de manera diferente según sus capacidades: + +**Triple Store de Cassandra:** +Utiliza la tabla `triples_collection` existente +Crea un triple de marcador de sistema cuando se crea una colección +Consulta: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1` +Comprobación de existencia de colección eficiente de partición única + +**Almacenes de vectores Qdrant/Milvus/Pinecone:** +Las API nativas de colección proporcionan la comprobación de existencia +Las colecciones se crean con la configuración de vectores adecuada +El método `collection_exists()` utiliza la API de almacenamiento +La creación de colecciones valida los requisitos de dimensión + +**Almacenes de grafos Neo4j/Memgraph/FalkorDB:** +Utiliza nodos `:CollectionMetadata` para realizar el seguimiento de las colecciones +Propiedades del nodo: `{user, collection, created_at}` +Consulta: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})` +Separado de los nodos de datos para una separación limpia +Permite una enumeración y validación eficientes de las colecciones + +**Almacén de objetos de Cassandra:** +Utiliza la tabla de metadatos de la colección o filas de marcador +Patrón similar al triple store +Valida la colección antes de las escrituras de documentos + +### API + +API de administración de colecciones (Bibliotecario): +**Crear/Actualizar colección**: Crear una nueva colección o actualizar los metadatos existentes a través de `tg-set-collection` +**Listar colecciones**: Recuperar colecciones para un usuario con filtrado opcional por etiqueta +**Eliminar colección**: Eliminar la colección y los datos asociados, propagándose a todos los tipos de tienda + +API de administración de almacenamiento (Todos los procesadores de almacenamiento): +**Crear colección**: Manejar la operación de "crear-colección", establecer la colección en el almacenamiento +**Eliminar colección**: Manejar la operación de "eliminar-colección", eliminar todos los datos de la colección +**Comprobación de existencia de colección**: Validación interna antes de aceptar operaciones de escritura + +API de operación de datos (Comportamiento modificado): +**API de escritura**: Validar que la colección exista antes de aceptar datos, devolver un error si no es así +**API de consulta**: Devolver resultados vacíos para colecciones inexistentes sin error + +### Detalles de implementación + +La implementación seguirá los patrones existentes de TrustGraph para la integración de servicios y la estructura de comandos de la CLI. + +#### Eliminación en cascada de colecciones + +Cuando un usuario inicia la eliminación de una colección a través del servicio de bibliotecario: + +1. **Validación de metadatos**: Verificar que la colección exista y que el usuario tenga permiso para eliminarla +2. **Propagación a tiendas**: El bibliotecario coordina la eliminación en todos los escritores de tiendas: + Escritor de almacenamiento de vectores: Eliminar incrustaciones e índices de vectores para el usuario y la colección + Escritor de almacenamiento de objetos: Eliminar documentos y archivos para el usuario y la colección + Escritor de triple store: Eliminar datos de grafos y triples para el usuario y la colección +3. **Limpieza de metadatos**: Eliminar el registro de metadatos de la colección de Cassandra +4. **Manejo de errores**: Si falla la eliminación de alguna tienda, mantener la coherencia a través de mecanismos de reversión o reintento + +#### Interfaz de administración de colecciones + +**⚠️ ENFOQUE ANTIGUO: REEMPLAZADO POR UN PATRÓN BASADO EN CONFIGURACIÓN** + +La arquitectura basada en colas descrita a continuación ha sido reemplazada por un enfoque basado en configuración que utiliza `CollectionConfigHandler`. Todos los backends de almacenamiento ahora reciben actualizaciones de colecciones a través de mensajes de configuración en lugar de colas de administración dedicadas. + +~~Todos los escritores de tiendas implementan una interfaz de administración de colecciones estandarizada con un esquema común:~~ + +~~**Esquema de mensaje (`StorageManagementRequest`):**~~ +```json +{ + "operation": "create-collection" | "delete-collection", + "user": "user123", + "collection": "documents-2024" +} +``` + +~~**Arquitectura de la Cola:**~~ +~~**Cola de Gestión de Almacenes Vectoriales** (`vector-storage-management`): Almacenes de vectores/incrustaciones~~ +~~**Cola de Gestión de Almacenes de Objetos** (`object-storage-management`): Almacenes de objetos/documentos~~ +~~**Cola de Gestión de Almacenes Triples** (`triples-storage-management`): Almacenes de grafos/RDF~~ +~~**Cola de Respuestas de Almacenamiento** (`storage-management-response`): Todas las respuestas se envían aquí~~ + +**Implementación Actual:** + +Todos los backends de almacenamiento ahora utilizan `CollectionConfigHandler`: +**Integración de Configuración Push**: Los servicios de almacenamiento se registran para recibir notificaciones de configuración push. +**Sincronización Automática**: Las colecciones se crean/eliminan en función de los cambios de configuración. +**Modelo Declarativo**: Las colecciones se definen en el servicio de configuración, y los backends se sincronizan para que coincidan. +**Sin Solicitud/Respuesta**: Elimina la sobrecarga de coordinación y el seguimiento de respuestas. +**Seguimiento del Estado de la Colección**: Se mantiene a través de la caché `known_collections`. +**Operaciones Idempotentes**: Es seguro procesar la misma configuración varias veces. + +Cada backend de almacenamiento implementa: +`create_collection(user: str, collection: str, metadata: dict)` - Crear estructuras de colección +`delete_collection(user: str, collection: str)` - Eliminar todos los datos de la colección +`collection_exists(user: str, collection: str) -> bool` - Validar antes de escribir + +#### Refactorización del Almacén Triples de Cassandra + +Como parte de esta implementación, el almacén triples de Cassandra se refactorizará de un modelo de una tabla por colección a un modelo de una tabla unificada: + +**Arquitectura Actual:** +Keyspace por usuario, tabla separada por colección +Esquema: `(s, p, o)` con `PRIMARY KEY (s, p, o)` +Nombres de tabla: las colecciones de usuario se convierten en tablas separadas de Cassandra. + +**Nueva Arquitectura:** +Keyspace por usuario, una sola tabla "triples" para todas las colecciones +Esquema: `(collection, s, p, o)` con `PRIMARY KEY (collection, s, p, o)` +Aislamiento de colecciones a través de la partición de colecciones + +**Cambios Requeridos:** + +1. **Refactorización de la Clase TrustGraph** (`trustgraph/direct/cassandra.py`): + Eliminar el parámetro `table` del constructor, usar la tabla "triples" fija. + Agregar el parámetro `collection` a todos los métodos. + Actualizar el esquema para incluir la colección como la primera columna. + **Actualizaciones de Índice**: Se crearán nuevos índices para admitir los 8 patrones de consulta: + Índice en `(s)` para consultas basadas en el sujeto. + Índice en `(p)` para consultas basadas en el predicado. + Índice en `(o)` para consultas basadas en el objeto. + Nota: Cassandra no admite índices secundarios de varias columnas, por lo que estos son índices de una sola columna. + + **Rendimiento del Patrón de Consulta:** + ✅ `get_all()` - escaneo de partición en `collection` + ✅ `get_s(s)` - utiliza la clave primaria de manera eficiente (`collection, s`) + ✅ `get_p(p)` - utiliza `idx_p` con `collection` de filtrado + ✅ `get_o(o)` - utiliza `idx_o` con `collection` de filtrado + ✅ `get_sp(s, p)` - utiliza la clave primaria de manera eficiente (`collection, s, p`) + ⚠️ `get_po(p, o)` - requiere `ALLOW FILTERING` (utiliza `idx_p` o `idx_o` más filtrado) + ✅ `get_os(o, s)` - utiliza `idx_o` con filtrado adicional en `s` + ✅ `get_spo(s, p, o)` - utiliza toda la clave primaria de manera eficiente + + **Nota sobre ALLOW FILTERING**: El patrón de consulta `get_po` requiere `ALLOW FILTERING` porque necesita tanto las restricciones de predicado como las de objeto sin un índice compuesto adecuado. Esto es aceptable porque este patrón de consulta es menos común que las consultas basadas en el sujeto en el uso típico de un almacén triples. + +2. **Actualizaciones del Escritor de Almacenamiento** (`trustgraph/storage/triples/cassandra/write.py`): + Mantener una única conexión TrustGraph por usuario en lugar de por (usuario, colección). + Pasar la colección a las operaciones de inserción. + Mejor utilización de recursos con menos conexiones. + +3. **Actualizaciones del Servicio de Consulta** (`trustgraph/query/triples/cassandra/service.py`): + Una única conexión TrustGraph por usuario. + Pasar la colección a todas las operaciones de consulta. + Mantener la misma lógica de consulta con el parámetro de colección. + +**Beneficios:** +**Eliminación Simplificada de Colecciones**: Eliminar utilizando la clave de partición `collection` en las 4 tablas. +**Eficiencia de Recursos**: Menos conexiones de base de datos y objetos de tabla. +**Operaciones entre Colecciones**: Más fácil de implementar operaciones que abarcan múltiples colecciones. +**Arquitectura Consistente**: Se alinea con el enfoque unificado de metadatos de colección. +**Validación de Colecciones**: Es fácil comprobar la existencia de la colección mediante la tabla `triples_collection`. + +Las operaciones de colección serán atómicas siempre que sea posible y proporcionarán un manejo de errores y una validación adecuados. + +## Consideraciones de seguridad + +Las operaciones de administración de colecciones requieren la autorización adecuada para evitar el acceso no autorizado o la eliminación de colecciones. El control de acceso se alineará con los modelos de seguridad de TrustGraph existentes. + +## Consideraciones de rendimiento + +Las operaciones de listado de colecciones pueden requerir paginación para entornos con un gran número de colecciones. Las consultas de metadatos deben optimizarse para patrones de filtrado comunes. + +## Estrategia de pruebas + +La prueba exhaustiva cubrirá: +Flujo de trabajo de creación de colecciones de extremo a extremo +Sincronización del almacenamiento en segundo plano +Validación de escritura para colecciones inexistentes +Manejo de consultas de colecciones inexistentes +Eliminación de colecciones en cascada en todos los almacenes +Manejo de errores y escenarios de recuperación +Pruebas unitarias para cada almacenamiento en segundo plano +Pruebas de integración para operaciones entre almacenes + +## Estado de la implementación + +### ✅ Componentes completados + +1. **Servicio de administración de colecciones Librarian** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`) + Operaciones CRUD de metadatos de colecciones (listar, actualizar, eliminar) + Integración de la tabla de metadatos de colecciones de Cassandra a través de `LibraryTableStore` + Coordinación de la eliminación de colecciones en cascada en todos los tipos de almacenamiento + Manejo de solicitudes/respuestas asíncronas con una gestión de errores adecuada + +2. **Esquema de metadatos de colecciones** (`trustgraph-base/trustgraph/schema/services/collection.py`) + Esquemas `CollectionManagementRequest` y `CollectionManagementResponse` + Esquema `CollectionMetadata` para registros de colecciones + Definiciones de temas de cola de solicitudes/respuestas de colecciones + +3. **Esquema de administración de almacenamiento** (`trustgraph-base/trustgraph/schema/services/storage.py`) + Esquemas `StorageManagementRequest` y `StorageManagementResponse` + Temas de cola de administración de almacenamiento definidos + Formato de mensaje para operaciones de colecciones a nivel de almacenamiento + +4. **Esquema de tabla Cassandra de 4 tablas** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`) + Claves de partición compuestas para el rendimiento de la consulta + Tabla `triples_collection` para consultas SPO y seguimiento de eliminación + Implementación de la eliminación de colecciones con el patrón de lectura y eliminación + +### ✅ Migración a patrón basado en configuración - COMPLETADO + +**Todos los backends de almacenamiento se han migrado del patrón basado en cola al patrón `CollectionConfigHandler` basado en configuración.** + +Migraciones completadas: +✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` + +Todos los backends ahora: +Heredan de `CollectionConfigHandler` +Se registran para notificaciones de configuración push a través de `self.register_config_handler(self.on_collection_config)` +Implementan `create_collection(user, collection, metadata)` y `delete_collection(user, collection)` +Utilizan `collection_exists(user, collection)` para validar antes de escribir +Se sincronizan automáticamente con los cambios del servicio de configuración + +Infraestructura basada en cola heredada eliminada: +✅ Esquemas `StorageManagementRequest` y `StorageManagementResponse` eliminados +✅ Definiciones de temas de cola de administración de almacenamiento eliminadas +✅ Consumidor/productor de administración de almacenamiento eliminado de todos los backends +✅ Manejadores `on_storage_management` eliminados de todos los backends + diff --git a/docs/tech-specs/collection-management.he.md b/docs/tech-specs/collection-management.he.md new file mode 100644 index 00000000..01f95254 --- /dev/null +++ b/docs/tech-specs/collection-management.he.md @@ -0,0 +1,403 @@ +# מפרט טכני לניהול אוספים + +## סקירה כללית + +מפרט זה מתאר את יכולות ניהול האוספים עבור TrustGraph, הדורש יצירת אוספים באופן מפורש ומספק שליטה ישירה על מחזור החיים של האוסף. יש ליצור אוספים באופן מפורש לפני השימוש, כדי להבטיח סנכרון תקין בין מטא-הנתונים של הספרן לבין כל אחסני הנתונים. הפיצ'ר תומך בארבעה תרחישי שימוש עיקריים: + +1. **יצירת אוסף**: ליצור אוספים באופן מפורש לפני אחסון נתונים +2. **רשימת אוספים**: להציג את כל האוספים הקיימים במערכת +3. **ניהול מטא-נתונים של אוסף**: לעדכן שמות, תיאורים ותגיות של אוספים +4. **מחיקת אוסף**: להסיר אוספים ונתונים הקשורים אליהם בכל סוגי האחסון + +## מטרות + +**יצירת אוסף מפורשת**: לדרוש יצירת אוספים לפני שאפשר לאחסן נתונים +**סנכרון אחסון**: להבטיח שאוספים קיימים בכל אחסני הנתונים (וקטורים, אובייקטים, טריפלטים) +**נראות של אוסף**: לאפשר למשתמשים לרשום ולבדוק את כל האוספים בסביבה שלהם +**ניקוי אוספים**: לאפשר מחיקת אוספים שכבר אינם נחוצים +**ארגון אוספים**: לתמוך בתגיות ובתוויות למעקב וגילוי טובים יותר של אוספים +**ניהול מטא-נתונים**: לקשר מטא-נתונים בעלי משמעות לאוספים לצורך בהירות תפעולית +**גילוי אוספים**: להקל על מציאת אוספים ספציפיים באמצעות סינון וחיפוש +**שקיפות תפעולית**: לספק נראות ברורה על מחזור החיים ושימוש האוספים +**ניהול משאבים**: לאפשר ניקוי של אוספים לא בשימוש כדי לייעל את ניצול המשאבים +**שלמות נתונים**: למנוע קיום של אוספים יתומים באחסון ללא מעקב מטא-נתונים + +## רקע + +בעבר, אוספים ב-TrustGraph נוצרו באופן סמוי במהלך פעולות טעינת נתונים, מה שגרם לבעיות סנכרון שבהן אוספים יכלו להתקיים באחסני נתונים ללא מטא-נתונים תואמים בספרן. זה יצר אתגרים בניהול ואפשרות של נתונים יתומים. + +מודל יצירת האוספים המפורש פותר בעיות אלה על ידי: +דרישה ליצירת אוספים לפני השימוש באמצעות `tg-set-collection` +שידור יצירת אוסף לכל אחסני הנתונים +שמירה על מצב מסונכרן בין מטא-נתונים של הספרן ואחסון +מניעת כתיבה לאוספים שאינם קיימים +מתן ניהול ברור של מחזור החיים של האוסף + +מפרט זה מגדיר את מודל ניהול האוספים המפורש. על ידי דרישה ליצירת אוסף מפורשת, TrustGraph מבטיחה: +אוספים מתועדים במטא-נתונים של הספרן החל מיצירתם +כל אחסני הנתונים מודעים לאוספים לפני קבלת נתונים +לא קיימים אוספים יתומים באחסון +נראות ושליטה ברורים על מחזור החיים של האוסף +טיפול שגיאות עקבי כאשר פעולות מפנות לאוספים שאינם קיימים + +## עיצוב טכני + +### ארכיטקטורה + +מערכת ניהול האוספים תיושם בתוך התשתית הקיימת של TrustGraph: + +1. **שילוב עם שירות הספרן** + פעולות ניהול אוספים יתווספו לשירות הספרן הקיים + לא נדרש שירות חדש - משתמש בדפוסי אימות וגישה קיימים + מטפל ברשימת אוספים, מחיקה וניהול מטא-נתונים + + מודול: trustgraph-librarian + +2. **טבלת מטא-נתונים של אוסף ב-Cassandra** + טבלה חדשה במרחב המפתחות הקיים של הספרן + מאחסנת מטא-נתונים של אוסף עם גישה מבוססת משתמש + מפתח ראשי: (user_id, collection_id) עבור ריבוי שוכרים תקין + + מודול: trustgraph-librarian + +3. **ממשק שורת פקודה לניהול אוספים** + ממשק שורת פקודה לפעולות ניהול אוספים + מספק פקודות לרשימה, מחיקה, תווית וניהול תגיות + משתלב עם מסגרת שורת הפקודה הקיימת + + מודול: trustgraph-cli + +### מודלים של נתונים + +#### טבלת מטא-נתונים של אוסף ב-Cassandra + +מטא-הנתונים של האוסף יאוחסנו בטבלה מובנית ב-Cassandra במרחב המפתחות של הספרן: + +```sql +CREATE TABLE collections ( + user text, + collection text, + name text, + description text, + tags set, + created_at timestamp, + updated_at timestamp, + PRIMARY KEY (user, collection) +); +``` + +מבנה טבלה: +**user** + **collection**: מפתח ראשי מורכב המבטיח בידוד משתמשים +**name**: שם קריא לבן-אדם של האוסף +**description**: תיאור מפורט של מטרת האוסף +**tags**: קבוצת תגיות למיון וסינון +**created_at**: חותמת זמן של יצירת האוסף +**updated_at**: חותמת זמן של השינוי האחרון + +גישה זו מאפשרת: +ניהול אוספים מרובי-דיירים עם בידוד משתמשים +שאילתות יעילות לפי משתמש ואוסף +מערכת תיוג גמישה לארגון +מעקב אחר מחזור החיים לצורך תובנות תפעוליות + +#### מחזור החיים של אוסף + +אוספים נוצרים באופן מפורש בספרן לפני שניתן לבצע פעולות נתונים: + +1. **יצירת אוסף** (שני מסלולים): + + **מסלול א': יצירה על ידי משתמש** באמצעות `tg-set-collection`: + המשתמש מספק מזהה אוסף, שם, תיאור ותגיות + הספרן יוצר רשומת מטא-נתונים בטבלת `collections` + הספרן משדר "create-collection" לכל מערכות האחסון + כל מעבדי האחסון יוצרים את האוסף ומאשרים הצלחה + האוסף מוכן כעת לפעולות נתונים + + **מסלול ב': יצירה אוטומטית בעת הגשת מסמך**: + המשתמש מגיש מסמך המציין מזהה אוסף + הספרן בודק אם האוסף קיים בטבלת המטא-נתונים + אם לא קיים: הספרן יוצר מטא-נתונים עם ברירות מחדל (שם=מזהה האוסף, תיאור/תגיות ריקים) + הספרן משדר "create-collection" לכל מערכות האחסון + כל מעבדי האחסון יוצרים את האוסף ומאשרים הצלחה + עיבוד המסמך ממשיך עם יצירת האוסף + + שני המסלולים מבטיחים שהאוסף קיים במטא-נתונים של הספרן ובכל מערכות האחסון לפני ביצוע פעולות נתונים. + +2. **אימות אחסון**: פעולות כתיבה מאמתות את קיומו של האוסף: + מעבדי האחסון בודקים את מצב האוסף לפני קבלת כתיבות + כתיבות לאוספים שאינם קיימים מחזירות שגיאה + זה מונע כתיבות ישירות העוקפות את לוגיקת יצירת האוסף של הספרן + +3. **התנהגות שאילתה**: פעולות שאילתה מטפלות באוספים שאינם קיימים בצורה חלקה: + שאילתות לאוספים שאינם קיימים מחזירות תוצאות ריקות + לא נזרקת שגיאה עבור פעולות שאילתה + מאפשרת חקירה מבלי לדרוש קיום האוסף + +4. **עדכוני מטא-נתונים**: משתמשים יכולים לעדכן מטא-נתונים של אוסף לאחר יצירתו: + עדכון שם, תיאור ותגיות באמצעות `tg-set-collection` + העדכונים חלים רק על מטא-נתונים של הספרן + מערכות האחסון שומרות על האוסף, אך עדכוני מטא-נתונים אינם מועברים + +5. **מחיקה מפורשת**: משתמשים מוחקים אוספים באמצעות `tg-delete-collection`: + הספרן משדר "delete-collection" לכל מערכות האחסון + ממתין לאישור מכל מעבדי האחסון + מוחק רשומת מטא-נתונים של הספרן רק לאחר השלמת הניקוי של האחסון + מבטיח שלא יישארו נתונים יתומים באחסון + +**עקרון מפתח**: הספרן הוא נקודת השליטה היחידה ליצירת אוספים. בין אם זהו פקודה של משתמש או הגשת מסמך, הספרן מבטיח מעקב נכון אחר מטא-נתונים וסנכרון של מערכות אחסון לפני שהוא מאפשר פעולות נתונים. + +פעולות נדרשות: +**יצירת אוסף**: פעולה של משתמש באמצעות `tg-set-collection` או אוטומטית בעת הגשת מסמך +**עדכון מטא-נתונים של אוסף**: פעולה של משתמש לשינוי שם, תיאור ותגיות +**מחיקת אוסף**: פעולה של משתמש להסרת אוסף ונתונים שלו בכל האחסונים +**רשימת אוספים**: פעולה של משתמש לצפייה באוספים עם סינון לפי תגיות + +#### ניהול אוספים מרובי-חנות + +אוספים קיימים על פני מספר מערכות אחסון ב-TrustGraph: +**מאגרי וקטורים** (Qdrant, Milvus, Pinecone): אחסון הטבעות ונתוני וקטור +**מאגרי אובייקטים** (Cassandra): אחסון מסמכים ונתוני קבצים +**מאגרי משולשים** (Cassandra, Neo4j, Memgraph, FalkorDB): אחסון נתוני גרף/RDF +פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא). +כל סוג חנות מיישם: +**מעקב אחר מצב איסוף**: שמירה על ידע אילו איסופים קיימים +**יצירת איסוף**: קבלת עיבוד פעולות "יצירת-איסוף" +**אימות איסוף**: בדיקת קיום האיסוף לפני קבלת כתיבות +**מחיקת איסוף**: הסרת כל הנתונים עבור איסוף מסוים + +שירות הספרין מתאם פעולות איסוף בין כל סוגי החנויות, תוך הבטחה ש: +איסופים נוצרים בכל ה-backends לפני השימוש +כל ה-backends מאשרים יצירה לפני החזרת הצלחה +מחזור חיים מסונכרן של איסופים בין סוגי אחסון +טיפול עקבי בשגיאות כאשר איסופים אינם קיימים + +#### מעקב אחר מצב איסוף לפי סוג אחסון + +כל backend אחסון עוקב אחר מצב איסוף בצורה שונה בהתאם ליכולותיו: + +**Cassandra Triple Store:** +משתמש בטבלה קיימת `triples_collection` +יוצר טריפל מערכת כאשר איסוף נוצר +שאילתה: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1` +בדיקה יעילה של מחיצה יחידה לקיום איסוף + +**Qdrant/Milvus/Pinecone Vector Stores:** +ממשקי API מקוריים לאיסופים מספקים בדיקת קיום +איסופים נוצרים עם תצורת וקטור מתאימה +שיטה `collection_exists()` משתמשת ב-API של האחסון +יצירת איסוף מאמת דרישות מימד + +**Neo4j/Memgraph/FalkorDB Graph Stores:** +משתמש בצמתים `:CollectionMetadata` כדי לעקוב אחר איסופים +מאפייני צומת: `{user, collection, created_at}` +שאילתה: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})` +נפרד מצמתי נתונים לצורך הפרדה נקייה +מאפשר רישום ואימות יעילים של איסופים + +**Cassandra Object Store:** +משתמש בטבלת מטא-נתונים של איסוף או שורות סימון +דפוס דומה ל-triple store +מאמת איסוף לפני כתיבת מסמכים + +### ממשקים + +ממשקי ניהול איסופים (ספרין): +**יצירת/עדכון איסוף**: יצירת איסוף חדש או עדכון מטא-נתונים קיימים באמצעות `tg-set-collection` +**רשימת איסופים**: שליפה של איסופים עבור משתמש עם סינון תגיות אופציונלי +**מחיקת איסוף**: הסרת איסוף ונתונים קשורים, עם העברה לכל סוגי החנויות + +ממשקי ניהול אחסון (כל מעבדי אחסון): +**יצירת איסוף**: טיפול בפעולת "יצירת-איסוף", הקמת איסוף באחסון +**מחיקת איסוף**: טיפול בפעולת "מחיקת-איסוף", הסרת כל נתוני איסוף +**בדיקת קיום איסוף**: אימות פנימי לפני קבלת פעולות כתיבה + +ממשקי פעולות נתונים (התנהגות משתנה): +**ממשקי כתיבה**: אימות קיום איסוף לפני קבלת נתונים, החזרת שגיאה אם לא קיים +**ממשקי שאילתה**: החזרת תוצאות ריקות עבור איסופים שאינם קיימים ללא שגיאה + +### פרטי יישום + +היישום יעקוב לדפוסי TrustGraph קיימים לשילוב שירותים ומבנה פקודות שורת פקודה. + +#### מחיקת איסוף בשרשרת + +כאשר משתמש יוזם מחיקת איסוף דרך שירות הספרין: + +1. **אימות מטא-נתונים**: אימות קיום איסוף ושהמשתמש מורשה למחוק +2. **שרשרת אחסון**: הספרין מתאם מחיקה בכל כותבי האחסון: + כותב אחסון וקטור: הסרת הטמעות ואינדקסים וקטוריים עבור המשתמש והאיסוף + כותב אחסון אובייקטים: הסרת מסמכים וקבצים עבור המשתמש והאיסוף + כותב triple store: הסרת נתוני גרף וטריפלים עבור המשתמש והאיסוף +3. **ניקוי מטא-נתונים**: הסרת רשומת מטא-נתונים של איסוף מ-Cassandra +4. **טיפול בשגיאות**: אם מחיקת אחסון כלשהי נכשלת, שמירה על עקביות באמצעות ביטול או מנגנוני ניסיון חוזר + +#### ממשק ניהול איסופים + +**⚠️ גישה מיושנת - הוחלפה בדפוס מבוסס תצורה** + +הארכיטקטורה המבוססת על תורים המתוארת להלן הוחלפה בגישה מבוססת תצורה באמצעות `CollectionConfigHandler`. כל ה-backends אחסון מקבלים כעת עדכוני איסופים באמצעות הודעות דחיפה לתצורה במקום תורי ניהול ייעודיים. + +~~כל כותבי האחסון מיישמים ממשק ניהול איסופים סטנדרטי עם סכימה משותפת:~~ + +~~**סכימת הודעה (`StorageManagementRequest`):**~~ +```json +{ + "operation": "create-collection" | "delete-collection", + "user": "user123", + "collection": "documents-2024" +} +``` + +~~**ארכיטקטורת תורים:**~~ +~~**תור ניהול מאגרי וקטורים** (`vector-storage-management`): מאגרי וקטורים/הטבעות~~ +~~**תור ניהול אחסון אובייקטים** (`object-storage-management`): אחסון אובייקטים/מסמכים~~ +~~**תור ניהול מאגרי טריפל** (`triples-storage-management`): מאגרי גרפים/RDF~~ +~~**תור תגובות אחסון** (`storage-management-response`): כל התגובות נשלחות לכאן~~ + +**יישום נוכחי:** + +כל מערכות האחסון משתמשות כעת ב-`CollectionConfigHandler`: +**אינטגרציה של דחיפת תצורה**: שירותי אחסון נרשמים לקבלת התראות על שינויי תצורה +**סנכרון אוטומטי**: אוספים נוצרים/נמחקים בהתבסס על שינויי תצורה +**מודל הצהרתי**: אוספים מוגדרים בשירות התצורה, מערכות האחסון מסתנכרנות כדי להתאים +**ללא בקשות/תגובות**: מבטל את התקורה של תיאום ומעקב אחר תגובות +**מעקב אחר מצב אוסף**: נשמר באמצעות מטמון `known_collections` +**פעולות אידמפוטנטיות**: בטוח לעבד את אותה תצורה מספר פעמים + +כל מערכת אחסון מיישמת: +`create_collection(user: str, collection: str, metadata: dict)` - יצירת מבני אוסף +`delete_collection(user: str, collection: str)` - הסרת כל נתוני האוסף +`collection_exists(user: str, collection: str) -> bool` - אימות לפני כתיבה + +#### שינוי מבנה מאגר טריפל של Cassandra + +כחלק מיישום זה, מאגר הטריפל של Cassandra ישונה ממודל של טבלה לכל אוסף למודל טבלה מאוחדת: + +**ארכיטקטורה נוכחית:** +מרחב מפתחות לכל משתמש, טבלה נפרדת לכל אוסף +סכימה: `(s, p, o)` עם `PRIMARY KEY (s, p, o)` +שמות טבלאות: אוספי משתמשים הופכים לטבלאות Cassandra נפרדות + +**ארכיטקטורה חדשה:** +מרחב מפתחות לכל משתמש, טבלה יחידה בשם "triples" לכל האוספים +סכימה: `(collection, s, p, o)` עם `PRIMARY KEY (collection, s, p, o)` +בידוד אוספים באמצעות חלוקה לאוספים + +**שינויים נדרשים:** + +1. **שינוי מבנה מחלקה TrustGraph** (`trustgraph/direct/cassandra.py`): + הסרת פרמטר `table` מהקונסטרוקטור, שימוש בטבלה קבועה "triples" + הוספת פרמטר `collection` לכל השיטות + עדכון הסכימה כדי לכלול את האוסף בעמודה הראשונה + **עדכוני אינדקסים**: ייוצרו אינדקסים חדשים לתמיכה בכל 8 דפוסי השאילתות: + אינדקס על `(s)` עבור שאילתות מבוססות סובייקט + אינדקס על `(p)` עבור שאילתות מבוססות פרידיקט + אינדקס על `(o)` עבור שאילתות מבוססות אובייקט + הערה: Cassandra אינה תומכת באינדקסים משניים רב-עמודתיים, לכן אלו הם אינדקסים בעמודה יחידה + + **ביצועי דפוסי שאילתות:** + ✅ `get_all()` - סריקת מחיצה על `collection` + ✅ `get_s(s)` - משתמשת ביעילות במפתח ראשי (`collection, s`) + ✅ `get_p(p)` - משתמשת ב-`idx_p` עם סינון `collection` + ✅ `get_o(o)` - משתמשת ב-`idx_o` עם סינון `collection` + ✅ `get_sp(s, p)` - משתמשת ביעילות במפתח ראשי (`collection, s, p`) + ⚠️ `get_po(p, o)` - דורשת `ALLOW FILTERING` (משתמשת או ב-`idx_p` או ב-`idx_o` בתוספת סינון) + ✅ `get_os(o, s)` - משתמשת ב-`idx_o` עם סינון נוסף על `s` + ✅ `get_spo(s, p, o)` - משתמשת ביעילות במפתח ראשי מלא + + **הערה על ALLOW FILTERING**: דפוס השאילתה `get_po` דורש `ALLOW FILTERING` מכיוון שהוא זקוק גם לאילוצי פרידיקט וגם לאובייקט ללא אינדקס מורכב מתאים. זה מקובל מכיוון שדפוס השאילתה הזה פחות נפוץ משאילתות מבוססות סובייקט בשימוש טיפוסי במאגר טריפל. + +2. **עדכוני כותב אחסון** (`trustgraph/storage/triples/cassandra/write.py`): + שמירה על חיבור TrustGraph יחיד לכל משתמש במקום לכל (משתמש, אוסף) + העברת האוסף לפעולות הכנסה + שיפור ניצול משאבים עם פחות חיבורים + +3. **עדכוני שירות שאילתות** (`trustgraph/query/triples/cassandra/service.py`): + חיבור TrustGraph יחיד לכל משתמש + העברת האוסף לכל פעולות השאילתה + שמירה על לוגיקת שאילתה זהה עם פרמטר האוסף + +**יתרונות:** +**מחיקת אוספים מפושטת:** מחיקה באמצעות מפתח מחיצה `collection` בכל 4 הטבלאות +**יעילות משאבים:** פחות חיבורי מסד נתונים ואובייקטי טבלה +**פעולות חוצות אוספים:** קל יותר ליישם פעולות המשתרעות על פני מספר אוספים +**ארכיטקטורה עקבית:** מתאימה לגישה מאוחדת למטא-נתונים של אוספים +**אימות אוסף:** קל לבדוק את קיום האוסף באמצעות טבלת `triples_collection` + +פעולות איסוף יהיו אטומיות במידת האפשר, ויספקו טיפול בשגיאות ואימות מתאימים. + +## שיקולי אבטחה + +פעולות ניהול איסוף דורשות הרשאות מתאימות כדי למנוע גישה או מחיקה לא מורשית של איסופים. בקרת הגישה תתאים למודלי האבטחה הקיימים של TrustGraph. + +## שיקולי ביצועים + +פעולות הצגת איסופים עשויות לדרוש דפוס של חלוקה לדפים (pagination) עבור סביבות עם מספר גדול של איסופים. שאילתות מטא-נתונים צריכות להיות מותאמות לשיטות סינון נפוצות. + +## אסטרטגיית בדיקות + +בדיקות מקיפות יכסו: +זרימת עבודה של יצירת איסוף מקצה לקצה +סנכרון עם ה-backend של האחסון +אימות כתיבה עבור איסופים שאינם קיימים +טיפול בשאילתות עבור איסופים שאינם קיימים +מחיקת איסוף עם השפעה על כל האחסונים +טיפול בשגיאות ותסריטי התאוששות +בדיקות יחידה עבור כל ה-backend של האחסון +בדיקות אינטגרציה עבור פעולות חוצות-אחסונים + +## סטטוס יישום + +### ✅ רכיבים שהושלמו + +1. **שירות ניהול איסופים של Librarian** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`) + פעולות CRUD של מטא-נתונים של איסוף (רשימה, עדכון, מחיקה) + שילוב עם טבלת מטא-נתונים של איסוף ב-Cassandra באמצעות `LibraryTableStore` + תיאום מחיקת איסוף עם השפעה על כל סוגי האחסון + טיפול בבקשות/תגובות אסינכרוניות עם ניהול שגיאות מתאים + +2. **סכימת מטא-נתונים של איסוף** (`trustgraph-base/trustgraph/schema/services/collection.py`) + סכימות `CollectionManagementRequest` ו-`CollectionManagementResponse` + סכימה `CollectionMetadata` עבור רשומות איסוף + הגדרות נושא תורים עבור בקשות/תגובות של איסוף + +3. **סכימת ניהול אחסון** (`trustgraph-base/trustgraph/schema/services/storage.py`) + סכימות `StorageManagementRequest` ו-`StorageManagementResponse` + נושאים של תורי ניהול אחסון הוגדרו + פורמט הודעה עבור פעולות של איסוף ברמת האחסון + +4. **סכימת 4-טבלאות של Cassandra** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`) + מפתחות מחיצה מורכבים לביצועי שאילתה + טבלה `triples_collection` עבור שאילתות SPO ומעקב אחר מחיקה + יישום מחיקת איסוף עם דפוס של קריאה ולאחר מכן מחיקה + +### ✅ מעבר לדפוס מבוסס תצורה - הושלם + +**כל ה-backend של האחסון עברו מדפוס מבוסס תורים לדפוס מבוסס תצורה `CollectionConfigHandler`.** + +מעברים שהושלמו: +✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` + +כל ה-backend כעת: +יורשים מ-`CollectionConfigHandler` +נרשמים לקבלת הודעות דחיפה של תצורה באמצעות `self.register_config_handler(self.on_collection_config)` +מיישמים `create_collection(user, collection, metadata)` ו-`delete_collection(user, collection)` +משתמשים ב-`collection_exists(user, collection)` לאימות לפני כתיבה +מסתנכרנים באופן אוטומטי עם שינויים בשירות התצורה + +תשתית מבוססת תורים ישנה הוסרה: +✅ הוסרו סכימות `StorageManagementRequest` ו-`StorageManagementResponse` +✅ הוסרו הגדרות נושאים של תורי ניהול אחסון +✅ הוסר צרכן/מפיק תורים מכל ה-backend +✅ הוסרו מטפלים `on_storage_management` מכל ה-backend + diff --git a/docs/tech-specs/collection-management.hi.md b/docs/tech-specs/collection-management.hi.md new file mode 100644 index 00000000..21107ca5 --- /dev/null +++ b/docs/tech-specs/collection-management.hi.md @@ -0,0 +1,403 @@ +# संग्रह प्रबंधन तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ के लिए संग्रह प्रबंधन क्षमताओं का वर्णन करता है, जिसमें स्पष्ट संग्रह निर्माण की आवश्यकता होती है और संग्रह जीवनचक्र पर प्रत्यक्ष नियंत्रण प्रदान किया जाता है। उपयोग से पहले संग्रहों को स्पष्ट रूप से बनाया जाना चाहिए, जिससे लाइब्रेरियन मेटाडेटा और सभी स्टोरेज बैकएंड के बीच उचित सिंक्रोनाइज़ेशन सुनिश्चित हो सके। यह सुविधा चार प्राथमिक उपयोग मामलों का समर्थन करती है: + +1. **संग्रह निर्माण**: डेटा संग्रहीत करने से पहले स्पष्ट रूप से संग्रह बनाएं +2. **संग्रह सूची**: सिस्टम में सभी मौजूदा संग्रह देखें +3. **संग्रह मेटाडेटा प्रबंधन**: संग्रह नामों, विवरणों और टैगों को अपडेट करें +4. **संग्रह विलोपन**: संग्रह और उनके संबंधित डेटा को सभी स्टोरेज प्रकारों से हटा दें + +## लक्ष्य + +**स्पष्ट संग्रह निर्माण**: डेटा संग्रहीत करने से पहले संग्रह बनाए जाने की आवश्यकता होती है +**स्टोरेज सिंक्रोनाइज़ेशन**: सुनिश्चित करें कि संग्रह सभी स्टोरेज बैकएंड (वेक्टर, ऑब्जेक्ट, ट्रिपल) में मौजूद हैं +**संग्रह दृश्यता**: उपयोगकर्ताओं को अपने वातावरण में सभी संग्रहों को सूचीबद्ध और निरीक्षण करने में सक्षम करें +**संग्रह सफाई**: अब आवश्यक नहीं होने वाले संग्रहों को हटाने की अनुमति दें +**संग्रह संगठन**: बेहतर संग्रह ट्रैकिंग और खोज के लिए लेबल और टैग का समर्थन करें +**मेटाडेटा प्रबंधन**: परिचालन स्पष्टता के लिए संग्रहों के साथ सार्थक मेटाडेटा संबद्ध करें +**संग्रह खोज**: फ़िल्टरिंग और खोज के माध्यम से विशिष्ट संग्रहों को खोजना आसान बनाएं +**परिचालन पारदर्शिता**: संग्रह जीवनचक्र और उपयोग में स्पष्ट दृश्यता प्रदान करें +**संसाधन प्रबंधन**: अप्रयुक्त संग्रहों को साफ करके संसाधन उपयोग को अनुकूलित करें +**डेटा अखंडता**: स्टोरेज में मेटाडेटा ट्रैकिंग के बिना अनाथ संग्रहों को रोकें + +## पृष्ठभूमि + +पहले, ट्रस्टग्राफ में संग्रह डेटा लोडिंग कार्यों के दौरान निहित रूप से बनाए जाते थे, जिससे सिंक्रोनाइज़ेशन संबंधी समस्याएं होती थीं, जहाँ संग्रह स्टोरेज बैकएंड में मौजूद हो सकते थे लेकिन लाइब्रेरियन में संबंधित मेटाडेटा नहीं होता था। इससे प्रबंधन में चुनौतियां और संभावित अनाथ डेटा उत्पन्न होता था। + +स्पष्ट संग्रह निर्माण मॉडल इन मुद्दों को संबोधित करता है: +`tg-set-collection` के माध्यम से उपयोग से पहले संग्रह बनाने की आवश्यकता होती है +सभी स्टोरेज बैकएंड में संग्रह निर्माण का प्रसारण +लाइब्रेरियन मेटाडेटा और स्टोरेज के बीच सिंक्रोनाइज़ स्थिति बनाए रखना +गैर-मौजूदा संग्रहों में लेखन को रोकना +स्पष्ट संग्रह जीवनचक्र प्रबंधन प्रदान करना + +यह विनिर्देश स्पष्ट संग्रह प्रबंधन मॉडल को परिभाषित करता है। स्पष्ट संग्रह निर्माण की आवश्यकता करके, ट्रस्टग्राफ यह सुनिश्चित करता है: +संग्रह निर्माण से लाइब्रेरियन मेटाडेटा में ट्रैक किए जाते हैं +सभी स्टोरेज बैकएंड डेटा प्राप्त करने से पहले संग्रहों के बारे में जानते हैं +स्टोरेज में कोई अनाथ संग्रह नहीं है +संग्रह जीवनचक्र पर स्पष्ट परिचालन दृश्यता और नियंत्रण +गैर-मौजूदा संग्रहों को संदर्भित करने वाले कार्यों के लिए सुसंगत त्रुटि हैंडलिंग + +## तकनीकी डिजाइन + +### वास्तुकला + +संग्रह प्रबंधन प्रणाली को मौजूदा ट्रस्टग्राफ बुनियादी ढांचे के भीतर लागू किया जाएगा: + +1. **लाइब्रेरियन सेवा एकीकरण** + संग्रह प्रबंधन संचालन मौजूदा लाइब्रेरियन सेवा में जोड़े जाएंगे + किसी नई सेवा की आवश्यकता नहीं है - मौजूदा प्रमाणीकरण और एक्सेस पैटर्न का लाभ उठाता है + संग्रह सूची, विलोपन और मेटाडेटा प्रबंधन को संभालता है + + मॉड्यूल: trustgraph-librarian + +2. **कैसेंड्रा संग्रह मेटाडेटा तालिका** + मौजूदा लाइब्रेरियन कीस्पेस में एक नई तालिका + उपयोगकर्ता-स्कोप किए गए एक्सेस के साथ संग्रह मेटाडेटा संग्रहीत करता है + प्राथमिक कुंजी: उचित मल्टी-टेनेंसी के लिए (user_id, collection_id) + + मॉड्यूल: trustgraph-librarian + +3. **संग्रह प्रबंधन CLI** + संग्रह संचालन के लिए कमांड-लाइन इंटरफ़ेस + सूची, हटाएं, लेबल और टैग प्रबंधन कमांड प्रदान करता है + मौजूदा CLI फ्रेमवर्क के साथ एकीकृत + + मॉड्यूल: trustgraph-cli + +### डेटा मॉडल + +#### कैसेंड्रा संग्रह मेटाडेटा तालिका + +संग्रह मेटाडेटा को लाइब्रेरियन कीस्पेस में एक संरचित कैसेंड्रा तालिका में संग्रहीत किया जाएगा: + +```sql +CREATE TABLE collections ( + user text, + collection text, + name text, + description text, + tags set, + created_at timestamp, + updated_at timestamp, + PRIMARY KEY (user, collection) +); +``` + +तालिका संरचना: +**user**: **collection**: समग्र प्राथमिक कुंजी जो उपयोगकर्ता अलगाव सुनिश्चित करती है +**name**: संग्रह का मानव-पठनीय नाम +**description**: संग्रह के उद्देश्य का विस्तृत विवरण +**tags**: वर्गीकरण और फ़िल्टरिंग के लिए टैग का सेट +**created_at**: संग्रह निर्माण का टाइमस्टैम्प +**updated_at**: अंतिम संशोधन टाइमस्टैम्प + +यह दृष्टिकोण अनुमति देता है: +उपयोगकर्ता अलगाव के साथ बहु-किरायेदार संग्रह प्रबंधन +उपयोगकर्ता और संग्रह द्वारा कुशल क्वेरी +संगठन के लिए लचीला टैगिंग सिस्टम +परिचालन अंतर्दृष्टि के लिए जीवनचक्र ट्रैकिंग + +#### संग्रह जीवनचक्र + +डेटा संचालन शुरू करने से पहले संग्रह को स्पष्ट रूप से लाइब्रेरियन में बनाया जाना चाहिए: + +1. **संग्रह निर्माण** (दो रास्ते): + + **रास्ता A: उपयोगकर्ता-आरंभित निर्माण** `tg-set-collection` के माध्यम से: + उपयोगकर्ता संग्रह आईडी, नाम, विवरण और टैग प्रदान करता है + लाइब्रेरियन `collections` तालिका में मेटाडेटा रिकॉर्ड बनाता है + लाइब्रेरियन सभी स्टोरेज बैकएंड पर "create-collection" प्रसारित करता है + सभी स्टोरेज प्रोसेसर संग्रह बनाते हैं और सफलता की पुष्टि करते हैं + संग्रह अब डेटा संचालन के लिए तैयार है + + **रास्ता B: दस्तावेज़ सबमिशन पर स्वचालित निर्माण**: + उपयोगकर्ता एक संग्रह आईडी निर्दिष्ट करते हुए एक दस्तावेज़ सबमिट करता है + लाइब्रेरियन जांचता है कि क्या संग्रह मेटाडेटा तालिका में मौजूद है + यदि मौजूद नहीं है: लाइब्रेरियन डिफ़ॉल्ट के साथ मेटाडेटा बनाता है (नाम = संग्रह_आईडी, खाली विवरण/टैग) + लाइब्रेरियन सभी स्टोरेज बैकएंड पर "create-collection" प्रसारित करता है + सभी स्टोरेज प्रोसेसर संग्रह बनाते हैं और सफलता की पुष्टि करते हैं + दस्तावेज़ प्रसंस्करण संग्रह स्थापित होने के साथ आगे बढ़ता है + + दोनों रास्ते यह सुनिश्चित करते हैं कि संग्रह लाइब्रेरियन मेटाडेटा में और सभी स्टोरेज बैकएंड में मौजूद है, डेटा संचालन से पहले। + +2. **भंडारण सत्यापन**: लेखन संचालन संग्रह के अस्तित्व को मान्य करते हैं: + स्टोरेज प्रोसेसर लेखन स्वीकार करने से पहले संग्रह की स्थिति की जांच करते हैं + गैर-मौजूदा संग्रह में लेखन त्रुटि लौटाते हैं + यह लाइब्रेरियन के संग्रह निर्माण तर्क को बायपास करने वाले सीधे लेखन को रोकता है + +3. **क्वेरी व्यवहार**: क्वेरी संचालन गैर-मौजूदा संग्रह को सुचारू रूप से संभालते हैं: + गैर-मौजूदा संग्रह में क्वेरी खाली परिणाम लौटाती है + कोई त्रुटि नहीं फेंकी जाती है क्वेरी संचालन के लिए + संग्रह के मौजूद होने की आवश्यकता के बिना अन्वेषण की अनुमति देता है + +4. **मेटाडेटा अपडेट**: उपयोगकर्ता निर्माण के बाद संग्रह मेटाडेटा को अपडेट कर सकते हैं: + `tg-set-collection` के माध्यम से नाम, विवरण और टैग अपडेट करें + अपडेट केवल लाइब्रेरियन मेटाडेटा पर लागू होते हैं + स्टोरेज बैकएंड संग्रह बनाए रखते हैं लेकिन मेटाडेटा अपडेट प्रसारित नहीं होते हैं + +5. **स्पष्ट विलोपन**: उपयोगकर्ता `tg-delete-collection` के माध्यम से संग्रह को हटाते हैं: + लाइब्रेरियन सभी स्टोरेज बैकएंड पर "delete-collection" प्रसारित करता है + सभी स्टोरेज प्रोसेसर से पुष्टिकरण की प्रतीक्षा करता है + केवल स्टोरेज क्लीनअप पूरा होने के बाद लाइब्रेरियन मेटाडेटा रिकॉर्ड को हटाता है + यह सुनिश्चित करता है कि कोई भी डेटा स्टोरेज में नहीं बचा है + +**मुख्य सिद्धांत**: लाइब्रेरियन संग्रह निर्माण के लिए एकल नियंत्रण बिंदु है। चाहे उपयोगकर्ता कमांड द्वारा शुरू किया गया हो या दस्तावेज़ सबमिशन द्वारा, लाइब्रेरियन डेटा संचालन की अनुमति देने से पहले उचित मेटाडेटा ट्रैकिंग और स्टोरेज बैकएंड सिंक्रोनाइज़ेशन सुनिश्चित करता है। + +आवश्यक संचालन: +**संग्रह बनाएं**: `tg-set-collection` के माध्यम से उपयोगकर्ता ऑपरेशन या दस्तावेज़ सबमिशन पर स्वचालित +**संग्रह मेटाडेटा अपडेट करें**: नाम, विवरण और टैग को संशोधित करने के लिए उपयोगकर्ता ऑपरेशन +**संग्रह हटाएं**: सभी स्टोर में संग्रह और उसके डेटा को हटाने के लिए उपयोगकर्ता ऑपरेशन +**संग्रह सूचीबद्ध करें**: टैग द्वारा फ़िल्टर करके संग्रह देखने के लिए उपयोगकर्ता ऑपरेशन + +#### मल्टी-स्टोर संग्रह प्रबंधन + +संग्रह ट्रस्टग्राफ में कई स्टोरेज बैकएंड में मौजूद हैं: +**वेक्टर स्टोर** (Qdrant, Milvus, Pinecone): एम्बेडिंग और वेक्टर डेटा संग्रहीत करें +**ऑब्जेक्ट स्टोर** (Cassandra): दस्तावेज़ और फ़ाइल डेटा संग्रहीत करें +**ट्रिपल स्टोर** (Cassandra, Neo4j, Memgraph, FalkorDB): ग्राफ/RDF डेटा संग्रहीत करें + +प्रत्येक स्टोर प्रकार निम्नलिखित लागू करता है: +**संग्रह स्थिति ट्रैकिंग**: यह जानकारी बनाए रखें कि कौन से संग्रह मौजूद हैं +**संग्रह निर्माण**: "संग्रह बनाएं" संचालन स्वीकार करें और संसाधित करें +**संग्रह सत्यापन**: लिखने को स्वीकार करने से पहले जांचें कि संग्रह मौजूद है या नहीं +**संग्रह विलोपन**: निर्दिष्ट संग्रह के लिए सभी डेटा हटाएं + +लाइब्रेरियन सेवा सभी स्टोर प्रकारों में संग्रह संचालन का समन्वय करती है, यह सुनिश्चित करते हुए: +सभी बैकएंड में संग्रह का निर्माण उपयोग से पहले किया जाता है +सभी बैकएंड निर्माण की पुष्टि करते हैं इससे पहले कि सफलता वापस की जाए +भंडारण प्रकारों में संग्रह जीवनचक्र का सिंक्रनाइज़ेशन +जब संग्रह मौजूद नहीं होते हैं तो सुसंगत त्रुटि हैंडलिंग + +#### संग्रहण स्थिति ट्रैकिंग, संग्रहण प्रकार द्वारा + +प्रत्येक संग्रहण बैकएंड अपनी क्षमताओं के आधार पर संग्रह स्थिति को अलग-अलग तरीके से ट्रैक करता है: + +**कैसेंड्रा ट्रिपल स्टोर:** +मौजूदा `triples_collection` तालिका का उपयोग करता है +संग्रह बनने पर सिस्टम मार्कर ट्रिपल बनाता है +क्वेरी: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1` +संग्रह के अस्तित्व की जांच के लिए कुशल सिंगल-पार्टिशन चेक + +**Qdrant/Milvus/Pinecone वेक्टर स्टोर:** +मूल संग्रह एपीआई अस्तित्व जांच प्रदान करते हैं +उचित वेक्टर कॉन्फ़िगरेशन के साथ संग्रह बनाए जाते हैं +`collection_exists()` विधि संग्रहण एपीआई का उपयोग करती है +संग्रह निर्माण आयाम आवश्यकताओं को मान्य करता है + +**Neo4j/Memgraph/FalkorDB ग्राफ स्टोर:** +संग्रह को ट्रैक करने के लिए `:CollectionMetadata` नोड्स का उपयोग करें +नोड गुण: `{user, collection, created_at}` +क्वेरी: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})` +डेटा नोड्स से अलग, स्पष्ट अलगाव के लिए +कुशल संग्रह लिस्टिंग और सत्यापन को सक्षम करता है + +**कैसेंड्रा ऑब्जेक्ट स्टोर:** +संग्रह मेटाडेटा तालिका या मार्कर पंक्तियों का उपयोग करता है +ट्रिपल स्टोर के समान पैटर्न +दस्तावेज़ लेखन से पहले संग्रह को मान्य करता है + +### एपीआई + +संग्रह प्रबंधन एपीआई (लाइब्रेरियन): +**संग्रह बनाएं/अपडेट करें**: `tg-set-collection` के माध्यम से एक नया संग्रह बनाएं या मौजूदा मेटाडेटा को अपडेट करें +**संग्रह सूचीबद्ध करें**: वैकल्पिक टैग फ़िल्टरिंग के साथ एक उपयोगकर्ता के लिए संग्रह पुनर्प्राप्त करें +**संग्रह हटाएं**: संग्रह और उससे जुड़े डेटा को हटाएं, सभी स्टोर प्रकारों में कैस्केड करें + +संग्रहण प्रबंधन एपीआई (सभी संग्रहण प्रोसेसर): +**संग्रह बनाएं**: "संग्रह बनाएं" ऑपरेशन को संभालें, संग्रहण में संग्रह स्थापित करें +**संग्रह हटाएं**: "संग्रह हटाएं" ऑपरेशन को संभालें, सभी संग्रह डेटा को हटाएं +**संग्रह मौजूद है जांच**: लेखन संचालन को स्वीकार करने से पहले आंतरिक सत्यापन + +डेटा ऑपरेशन एपीआई (संशोधित व्यवहार): +**लिखने एपीआई**: डेटा स्वीकार करने से पहले जांचें कि संग्रह मौजूद है या नहीं, यदि नहीं तो त्रुटि लौटाएं +**क्वेरी एपीआई**: त्रुटि के बिना गैर-मौजूद संग्रह के लिए खाली परिणाम लौटाएं + +### कार्यान्वयन विवरण + +कार्यान्वयन सेवा एकीकरण और CLI कमांड संरचना के लिए मौजूदा ट्रस्टग्राफ पैटर्न का पालन करेगा। + +#### संग्रह विलोपन कैस्केड + +जब कोई उपयोगकर्ता लाइब्रेरियन सेवा के माध्यम से संग्रह विलोपन शुरू करता है: + +1. **मेटाडेटा सत्यापन**: सत्यापित करें कि संग्रह मौजूद है और उपयोगकर्ता के पास हटाने की अनुमति है +2. **स्टोर कैस्केड**: लाइब्रेरियन सभी स्टोर लेखकों में विलोपन का समन्वय करता है: + वेक्टर स्टोर लेखक: उपयोगकर्ता और संग्रह के लिए एम्बेडिंग और वेक्टर इंडेक्स हटाएं + ऑब्जेक्ट स्टोर लेखक: उपयोगकर्ता और संग्रह के लिए दस्तावेज़ और फ़ाइलें हटाएं + ट्रिपल स्टोर लेखक: उपयोगकर्ता और संग्रह के लिए ग्राफ डेटा और ट्रिपल हटाएं +3. **मेटाडेटा सफाई**: कैसेंड्रा से संग्रह मेटाडेटा रिकॉर्ड हटाएं +4. **त्रुटि हैंडलिंग**: यदि किसी भी स्टोर विलोपन में विफलता होती है, तो रोलबैक या पुनः प्रयास तंत्र के माध्यम से स्थिरता बनाए रखें + +#### संग्रह प्रबंधन इंटरफ़ेस + +⚠️ लेगेसी अप्रोच - कॉन्फ़िग-आधारित पैटर्न द्वारा प्रतिस्थापित + +नीचे वर्णित कतार-आधारित आर्किटेक्चर को `CollectionConfigHandler` का उपयोग करके एक कॉन्फ़िग-आधारित दृष्टिकोण से बदल दिया गया है। अब सभी संग्रहण बैकएंड समर्पित प्रबंधन कतारों के बजाय कॉन्फ़िग पुश संदेशों के माध्यम से संग्रह अपडेट प्राप्त करते हैं। + +~~सभी स्टोर लेखक एक मानकीकृत संग्रह प्रबंधन इंटरफ़ेस को लागू करते हैं जिसमें एक सामान्य स्कीमा है:~~ + +~~**संदेश स्कीमा (`StorageManagementRequest`):~~ +```json +{ + "operation": "create-collection" | "delete-collection", + "user": "user123", + "collection": "documents-2024" +} +``` + +~~**क्यू आर्किटेक्चर:**~~ +~~**वेक्टर स्टोर मैनेजमेंट क्यू** (`vector-storage-management`): वेक्टर/एम्बेडिंग स्टोर~~ +~~**ऑब्जेक्ट स्टोर मैनेजमेंट क्यू** (`object-storage-management`): ऑब्जेक्ट/डॉक्यूमेंट स्टोर~~ +~~**ट्रिपल स्टोर मैनेजमेंट क्यू** (`triples-storage-management`): ग्राफ/आरडीएफ स्टोर~~ +~~**स्टोरेज रिस्पांस क्यू** (`storage-management-response`): सभी प्रतिक्रियाएं यहां भेजी जाती हैं~~ + +**वर्तमान कार्यान्वयन:** + +सभी स्टोरेज बैकएंड अब `CollectionConfigHandler` का उपयोग करते हैं: +**कॉन्फ़िग पुश इंटीग्रेशन**: स्टोरेज सेवाएं कॉन्फ़िग पुश नोटिफिकेशन के लिए पंजीकरण करती हैं +**स्वचालित सिंक्रोनाइज़ेशन**: कॉन्फ़िग परिवर्तनों के आधार पर संग्रह बनाए/हटाए जाते हैं +**घोषणात्मक मॉडल**: संग्रह कॉन्फ़िग सेवा में परिभाषित हैं, बैकएंड मिलान के लिए सिंक्रोनाइज़ होते हैं +**कोई अनुरोध/प्रतिक्रिया नहीं**: समन्वय ओवरहेड और प्रतिक्रिया ट्रैकिंग को समाप्त करता है +**संग्रह स्थिति ट्रैकिंग**: `known_collections` कैश के माध्यम से बनाए रखा जाता है +**आइडेंपोटेंट ऑपरेशन**: एक ही कॉन्फ़िग को कई बार संसाधित करना सुरक्षित है + +प्रत्येक स्टोरेज बैकएंड लागू करता है: +`create_collection(user: str, collection: str, metadata: dict)` - संग्रह संरचनाएं बनाएं +`delete_collection(user: str, collection: str)` - सभी संग्रह डेटा हटाएं +`collection_exists(user: str, collection: str) -> bool` - लिखने से पहले मान्य करें + +#### कैसेंड्रा ट्रिपल स्टोर रीफैक्टर + +इस कार्यान्वयन के हिस्से के रूप में, कैसेंड्रा ट्रिपल स्टोर को एक टेबल-प्रति-संग्रह मॉडल से एक एकीकृत टेबल मॉडल में रीफैक्टर किया जाएगा: + +**वर्तमान आर्किटेक्चर:** +प्रति उपयोगकर्ता की स्पेस, प्रत्येक संग्रह के लिए अलग टेबल +स्कीमा: `(s, p, o)` with `PRIMARY KEY (s, p, o)` +टेबल नाम: उपयोगकर्ता संग्रह अलग-अलग कैसेंड्रा टेबल बन जाते हैं + +**नया आर्किटेक्चर:** +प्रति उपयोगकर्ता की स्पेस, सभी संग्रहों के लिए एक सिंगल "ट्रिपल्स" टेबल +स्कीमा: `(collection, s, p, o)` with `PRIMARY KEY (collection, s, p, o)` +संग्रह विभाजन के माध्यम से संग्रह अलगाव + +**आवश्यक परिवर्तन:** + +1. **ट्रस्टग्राफ क्लास रीफैक्टर** (`trustgraph/direct/cassandra.py`): + कंस्ट्रक्टर से `table` पैरामीटर हटाएं, फिक्स्ड "ट्रिपल्स" टेबल का उपयोग करें + सभी विधियों में `collection` पैरामीटर जोड़ें + स्कीमा को संग्रह को पहले कॉलम के रूप में शामिल करने के लिए अपडेट करें + **इंडेक्स अपडेट**: सभी 8 क्वेरी पैटर्न का समर्थन करने के लिए नए इंडेक्स बनाए जाएंगे: + विषय-आधारित प्रश्नों के लिए `(s)` पर इंडेक्स + विधेय-आधारित प्रश्नों के लिए `(p)` पर इंडेक्स + ऑब्जेक्ट-आधारित प्रश्नों के लिए `(o)` पर इंडेक्स + ध्यान दें: कैसेंड्रा मल्टी-कॉलम सेकेंडरी इंडेक्स का समर्थन नहीं करता है, इसलिए ये सिंगल-कॉलम इंडेक्स हैं + + **क्वेरी पैटर्न प्रदर्शन:** + ✅ `get_all()` - `collection` पर विभाजन स्कैन + ✅ `get_s(s)` - प्राथमिक कुंजी का कुशलतापूर्वक उपयोग करता है (`collection, s`) + ✅ `get_p(p)` - `idx_p` का उपयोग `collection` फ़िल्टरिंग के साथ + ✅ `get_o(o)` - `idx_o` का उपयोग `collection` फ़िल्टरिंग के साथ + ✅ `get_sp(s, p)` - प्राथमिक कुंजी का कुशलतापूर्वक उपयोग करता है (`collection, s, p`) + ⚠️ `get_po(p, o)` - `ALLOW FILTERING` की आवश्यकता है (या तो `idx_p` या `idx_o` प्लस फ़िल्टरिंग का उपयोग करता है) + ✅ `get_os(o, s)` - `idx_o` का उपयोग अतिरिक्त फ़िल्टरिंग के साथ `s` पर + ✅ `get_spo(s, p, o)` - पूरी प्राथमिक कुंजी का कुशलतापूर्वक उपयोग करता है + + **ALLOW FILTERING पर नोट:** `get_po` क्वेरी पैटर्न को `ALLOW FILTERING` की आवश्यकता होती है क्योंकि इसे उपयुक्त कंपाउंड इंडेक्स के बिना विधेय और ऑब्जेक्ट बाधाओं दोनों की आवश्यकता होती है। यह स्वीकार्य है क्योंकि यह क्वेरी पैटर्न विशिष्ट ट्रिपल स्टोर उपयोग में विषय-आधारित प्रश्नों की तुलना में कम सामान्य है + +2. **स्टोरेज राइटर अपडेट** (`trustgraph/storage/triples/cassandra/write.py`): + प्रति (उपयोगकर्ता, संग्रह) के बजाय प्रति उपयोगकर्ता सिंगल ट्रस्टग्राफ कनेक्शन बनाए रखें + सम्मिलित कार्यों में संग्रह पास करें + कम कनेक्शन के साथ बेहतर संसाधन उपयोग + +3. **क्वेरी सर्विस अपडेट** (`trustgraph/query/triples/cassandra/service.py`): + प्रति उपयोगकर्ता सिंगल ट्रस्टग्राफ कनेक्शन + सभी क्वेरी कार्यों में संग्रह पास करें + संग्रह पैरामीटर के साथ समान क्वेरी लॉजिक बनाए रखें + +**लाभ:** +**सरलीकृत संग्रह विलोपन:** सभी 4 तालिकाओं में `collection` विभाजन कुंजी का उपयोग करके हटाएं +**संसाधन दक्षता:** कम डेटाबेस कनेक्शन और टेबल ऑब्जेक्ट +**क्रॉस-संग्रह संचालन:** कई संग्रहों को कवर करने वाले संचालन को लागू करना आसान है +**संगत आर्किटेक्चर:** एकीकृत संग्रह मेटाडेटा दृष्टिकोण के साथ संरेखित +**संग्रह सत्यापन:** `triples_collection` टेबल के माध्यम से संग्रह अस्तित्व की जांच करना आसान है + +संग्रह संचालन संभव होने पर परमाणु होंगे और उचित त्रुटि प्रबंधन और सत्यापन प्रदान करेंगे। + +## सुरक्षा संबंधी विचार + +संग्रह प्रबंधन कार्यों के लिए उचित प्राधिकरण की आवश्यकता होती है ताकि अनधिकृत पहुंच या संग्रहों के हटाने को रोका जा सके। पहुंच नियंत्रण मौजूदा ट्रस्टग्राफ सुरक्षा मॉडल के अनुरूप होगा। + +## प्रदर्शन संबंधी विचार + +बड़ी संख्या में संग्रहों वाले वातावरण में संग्रह सूची संचालन के लिए पेजिंग की आवश्यकता हो सकती है। सामान्य फ़िल्टरिंग पैटर्न के लिए मेटाडेटा प्रश्नों को अनुकूलित किया जाना चाहिए। + +## परीक्षण रणनीति + +व्यापक परीक्षण में शामिल होंगे: +संग्रह निर्माण वर्कफ़्लो का एंड-टू-एंड परीक्षण +स्टोरेज बैकएंड सिंक्रोनाइज़ेशन +गैर-मौजूदा संग्रहों के लिए लेखन सत्यापन +गैर-मौजूदा संग्रहों के लिए क्वेरी हैंडलिंग +सभी स्टोरों में संग्रह हटाने का क्रम +त्रुटि प्रबंधन और पुनर्प्राप्ति परिदृश्य +प्रत्येक स्टोरेज बैकएंड के लिए यूनिट परीक्षण +क्रॉस-स्टोर संचालन के लिए एकीकरण परीक्षण + +## कार्यान्वयन स्थिति + +### ✅ पूर्ण घटक + +1. **लाइब्रेरियन संग्रह प्रबंधन सेवा** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`) + संग्रह मेटाडेटा CRUD संचालन (सूची, अपडेट, हटाएं) + `LibraryTableStore` के माध्यम से कैसेंड्रा संग्रह मेटाडेटा तालिका एकीकरण + सभी स्टोरेज प्रकारों में संग्रह हटाने का समन्वय + उचित त्रुटि प्रबंधन के साथ एसिंक्रोनस अनुरोध/प्रतिक्रिया हैंडलिंग + +2. **संग्रह मेटाडेटा स्कीमा** (`trustgraph-base/trustgraph/schema/services/collection.py`) + `CollectionManagementRequest` और `CollectionManagementResponse` स्कीमा + संग्रह रिकॉर्ड के लिए `CollectionMetadata` स्कीमा + संग्रह अनुरोध/प्रतिक्रिया कतार विषय परिभाषाएँ + +3. **स्टोरेज प्रबंधन स्कीमा** (`trustgraph-base/trustgraph/schema/services/storage.py`) + `StorageManagementRequest` और `StorageManagementResponse` स्कीमा + स्टोरेज प्रबंधन कतार विषय परिभाषित + स्टोरेज-स्तरीय संग्रह संचालन के लिए संदेश प्रारूप + +4. **कैसेंड्रा 4-टेबल स्कीमा** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`) + क्वेरी प्रदर्शन के लिए कंपाउंड पार्टीशन कुंजी + SPO प्रश्नों और हटाने ट्रैकिंग के लिए `triples_collection` तालिका + संग्रह हटाने को रीड-देन-डिलीट पैटर्न के साथ लागू किया गया + +### ✅ कॉन्फ़िग-आधारित पैटर्न में माइग्रेशन - पूर्ण + +**सभी स्टोरेज बैकएंड को कतार-आधारित पैटर्न से कॉन्फ़िग-आधारित `CollectionConfigHandler` पैटर्न में माइग्रेट किया गया है।** + +माइग्रेशन पूर्ण: +✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` + +सभी बैकएंड अब: +`CollectionConfigHandler` से विरासत में मिला है +`self.register_config_handler(self.on_collection_config)` के माध्यम से कॉन्फ़िग पुश नोटिफिकेशन के लिए पंजीकरण करें +`create_collection(user, collection, metadata)` और `delete_collection(user, collection)` को लागू करें +लिखने से पहले `collection_exists(user, collection)` का उपयोग करके सत्यापन करें +कॉन्फ़िग सेवा परिवर्तनों के साथ स्वचालित रूप से सिंक करें + +विरासत कतार-आधारित बुनियादी ढांचा हटाया गया: +✅ `StorageManagementRequest` और `StorageManagementResponse` स्कीमा हटाए गए +✅ स्टोरेज प्रबंधन कतार विषय परिभाषाएँ हटाई गईं +✅ सभी बैकएंड से स्टोरेज प्रबंधन उपभोक्ता/उत्पादक हटाए गए +✅ सभी बैकएंड से `on_storage_management` हैंडलर हटाए गए + diff --git a/docs/tech-specs/collection-management.pt.md b/docs/tech-specs/collection-management.pt.md new file mode 100644 index 00000000..ec5d62b2 --- /dev/null +++ b/docs/tech-specs/collection-management.pt.md @@ -0,0 +1,403 @@ +# Especificação Técnica de Gerenciamento de Coleções + +## Visão Geral + +Esta especificação descreve as capacidades de gerenciamento de coleções para o TrustGraph, exigindo a criação explícita de coleções e fornecendo controle direto sobre o ciclo de vida da coleção. As coleções devem ser criadas explicitamente antes de serem usadas, garantindo a sincronização adequada entre os metadados do bibliotecário e todos os backends de armazenamento. O recurso suporta quatro casos de uso primários: + +1. **Criação de Coleção**: Crie explicitamente coleções antes de armazenar dados +2. **Listagem de Coleções**: Visualize todas as coleções existentes no sistema +3. **Gerenciamento de Metadados da Coleção**: Atualize nomes, descrições e tags de coleções +4. **Exclusão de Coleções**: Remova coleções e seus dados associados em todos os tipos de armazenamento + +## Objetivos + +**Criação Explícita de Coleção**: Exigir que as coleções sejam criadas antes que os dados possam ser armazenados +**Sincronização de Armazenamento**: Garantir que as coleções existam em todos os backends de armazenamento (vetores, objetos, triplas) +**Visibilidade da Coleção**: Permitir que os usuários listem e inspecionem todas as coleções em seu ambiente +**Limpeza de Coleções**: Permitir a exclusão de coleções que não são mais necessárias +**Organização de Coleções**: Suportar rótulos e tags para melhor rastreamento e descoberta de coleções +**Gerenciamento de Metadados**: Associar metadados significativos às coleções para clareza operacional +**Descoberta de Coleções**: Facilitar a localização de coleções específicas por meio de filtragem e pesquisa +**Transparência Operacional**: Fornecer visibilidade clara do ciclo de vida e do uso da coleção +**Gerenciamento de Recursos**: Permitir a limpeza de coleções não utilizadas para otimizar a utilização de recursos +**Integridade de Dados**: Impedir a criação de coleções órfãs no armazenamento sem rastreamento de metadados + +## Contexto + +Anteriormente, as coleções no TrustGraph eram criadas implicitamente durante as operações de carregamento de dados, levando a problemas de sincronização em que as coleções poderiam existir em backends de armazenamento sem metadados correspondentes no bibliotecário. Isso criava desafios de gerenciamento e dados órfãos. + +O modelo de criação explícita de coleções aborda esses problemas: +Exigindo que as coleções sejam criadas antes de serem usadas via `tg-set-collection` +Transmitindo a criação da coleção para todos os backends de armazenamento +Mantendo um estado sincronizado entre os metadados do bibliotecário e o armazenamento +Impedindo a gravação em coleções inexistentes +Fornecendo gerenciamento claro do ciclo de vida da coleção + +Esta especificação define o modelo de gerenciamento explícito de coleções. Ao exigir a criação explícita de coleções, o TrustGraph garante: +Que as coleções sejam rastreadas nos metadados do bibliotecário desde a criação +Que todos os backends de armazenamento estejam cientes das coleções antes de receber dados +Que não existam coleções órfãs no armazenamento +Visibilidade e controle operacionais claros sobre o ciclo de vida da coleção +Tratamento de erros consistente quando as operações referenciam coleções inexistentes + +## Design Técnico + +### Arquitetura + +O sistema de gerenciamento de coleções será implementado dentro da infraestrutura existente do TrustGraph: + +1. **Integração do Serviço do Bibliotecário** + As operações de gerenciamento de coleções serão adicionadas ao serviço do bibliotecário existente + Nenhum novo serviço é necessário - aproveita os padrões de autenticação e acesso existentes + Lida com a listagem, exclusão e gerenciamento de metadados de coleções + + Módulo: trustgraph-librarian + +2. **Tabela de Metadados de Coleção do Cassandra** + Nova tabela no keyspace existente do bibliotecário + Armazena metadados da coleção com acesso específico ao usuário + Chave primária: (user_id, collection_id) para multilocação adequada + + Módulo: trustgraph-librarian + +3. **CLI de Gerenciamento de Coleções** + Interface de linha de comando para operações de coleção + Fornece comandos de listagem, exclusão, rotulagem e gerenciamento de tags + Integra-se com o framework de CLI existente + + Módulo: trustgraph-cli + +### Modelos de Dados + +#### Tabela de Metadados de Coleção do Cassandra + +Os metadados da coleção serão armazenados em uma tabela estruturada do Cassandra no keyspace do bibliotecário: + +```sql +CREATE TABLE collections ( + user text, + collection text, + name text, + description text, + tags set, + created_at timestamp, + updated_at timestamp, + PRIMARY KEY (user, collection) +); +``` + +Estrutura da tabela: +**user** + **collection**: Chave primária composta que garante o isolamento do usuário +**name**: Nome da coleção legível por humanos +**description**: Descrição detalhada do propósito da coleção +**tags**: Conjunto de tags para categorização e filtragem +**created_at**: Timestamp de criação da coleção +**updated_at**: Timestamp da última modificação + +Esta abordagem permite: +Gerenciamento de coleções multi-tenant com isolamento de usuário +Consulta eficiente por usuário e coleção +Sistema de tags flexível para organização +Rastreamento do ciclo de vida para insights operacionais + +#### Ciclo de Vida da Coleção + +As coleções são explicitamente criadas no gerenciador antes que as operações de dados possam prosseguir: + +1. **Criação da Coleção** (Dois Caminhos): + + **Caminho A: Criação Iniciada pelo Usuário** via `tg-set-collection`: + O usuário fornece o ID da coleção, nome, descrição e tags + O gerenciador cria um registro de metadados na tabela `collections` + O gerenciador transmite "create-collection" para todos os backends de armazenamento + Todos os processadores de armazenamento criam a coleção e confirmam o sucesso + A coleção está agora pronta para operações de dados + + **Caminho B: Criação Automática na Submissão de Documento**: + O usuário submete um documento especificando um ID de coleção + O gerenciador verifica se a coleção existe na tabela de metadados + Se não existir: O gerenciador cria metadados com valores padrão (nome=collection_id, descrição/tags vazias) + O gerenciador transmite "create-collection" para todos os backends de armazenamento + Todos os processadores de armazenamento criam a coleção e confirmam o sucesso + O processamento do documento prossegue com a coleção agora estabelecida + + Ambos os caminhos garantem que a coleção exista nos metadados do gerenciador E em todos os backends de armazenamento antes de permitir operações de dados. + +2. **Validação de Armazenamento**: As operações de escrita validam se a coleção existe: + Os processadores de armazenamento verificam o estado da coleção antes de aceitar escritas + As escritas em coleções inexistentes retornam um erro + Isso impede que as escritas contornem a lógica de criação de coleção do gerenciador + +3. **Comportamento da Consulta**: As operações de consulta lidam com coleções inexistentes de forma elegante: + As consultas em coleções inexistentes retornam resultados vazios + Nenhum erro é lançado para operações de consulta + Permite a exploração sem exigir que a coleção exista + +4. **Atualizações de Metadados**: Os usuários podem atualizar os metadados da coleção após a criação: + Atualize o nome, a descrição e as tags via `tg-set-collection` + As atualizações se aplicam apenas aos metadados do gerenciador + Os backends de armazenamento mantêm a coleção, mas as atualizações de metadados não são propagadas + +5. **Exclusão Explícita**: Os usuários excluem coleções via `tg-delete-collection`: + O gerenciador transmite "delete-collection" para todos os backends de armazenamento + Aguarda a confirmação de todos os processadores de armazenamento + Exclui o registro de metadados do gerenciador somente após a limpeza do armazenamento estar completa + Garante que nenhum dado órfão permaneça no armazenamento + +**Princípio Chave**: O gerenciador é o ponto de controle único para a criação de coleções. Seja iniciada por um comando do usuário ou pela submissão de um documento, o gerenciador garante o rastreamento adequado de metadados e a sincronização do backend de armazenamento antes de permitir operações de dados. + +Operações necessárias: +**Criar Coleção**: Operação do usuário via `tg-set-collection` OU automática na submissão de documento +**Atualizar Metadados da Coleção**: Operação do usuário para modificar o nome, a descrição e as tags +**Excluir Coleção**: Operação do usuário para remover a coleção e seus dados em todos os armazenamentos +**Listar Coleções**: Operação do usuário para visualizar coleções com filtragem por tags + +#### Gerenciamento de Coleções em Múltiplos Armazenamentos + +As coleções existem em vários backends de armazenamento no TrustGraph: +**Vector Stores** (Qdrant, Milvus, Pinecone): Armazena embeddings e dados vetoriais +**Object Stores** (Cassandra): Armazena documentos e dados de arquivos +**Triple Stores** (Cassandra, Neo4j, Memgraph, FalkorDB): Armazena dados de grafo/RDF + +Cada tipo de armazenamento implementa: +**Rastreamento do Estado da Coleção**: Manter o conhecimento de quais coleções existem +**Criação de Coleção**: Aceitar e processar operações de "criar-coleção" +**Validação de Coleção**: Verificar se a coleção existe antes de aceitar gravações +**Exclusão de Coleção**: Remover todos os dados para a coleção especificada + +O serviço de bibliotecário coordena as operações de coleção em todos os tipos de armazenamento, garantindo: +Que as coleções sejam criadas em todos os backends antes de serem usadas +Que todos os backends confirmem a criação antes de retornar o sucesso +Ciclo de vida da coleção sincronizado em todos os tipos de armazenamento +Tratamento de erros consistente quando as coleções não existem + +#### Rastreamento do Estado da Coleção por Tipo de Armazenamento + +Cada backend de armazenamento rastreia o estado da coleção de forma diferente, com base em suas capacidades: + +**Cassandra Triple Store:** +Usa a tabela `triples_collection` existente +Cria um triple de marcador do sistema quando a coleção é criada +Consulta: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1` +Verificação de existência de coleção eficiente de partição única + +**Qdrant/Milvus/Pinecone Vector Stores:** +As APIs nativas de coleção fornecem verificação de existência +Coleções criadas com configuração de vetor adequada +O método `collection_exists()` usa a API de armazenamento +A criação da coleção valida os requisitos de dimensão + +**Neo4j/Memgraph/FalkorDB Graph Stores:** +Usa nós `:CollectionMetadata` para rastrear coleções +Propriedades do nó: `{user, collection, created_at}` +Consulta: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})` +Separado de nós de dados para uma separação limpa +Permite listagem e validação eficientes de coleções + +**Cassandra Object Store:** +Usa a tabela de metadados da coleção ou linhas de marcador +Padrão semelhante ao triple store +Valida a coleção antes das gravações de documentos + +### APIs + +APIs de Gerenciamento de Coleção (Bibliotecário): +**Criar/Atualizar Coleção**: Criar uma nova coleção ou atualizar metadados existentes via `tg-set-collection` +**Listar Coleções**: Recuperar coleções para um usuário com filtragem opcional por tag +**Excluir Coleção**: Remover a coleção e os dados associados, propagando para todos os tipos de armazenamento + +APIs de Gerenciamento de Armazenamento (Todos os Processadores de Armazenamento): +**Criar Coleção**: Lidar com a operação de "criar-coleção", estabelecer a coleção no armazenamento +**Excluir Coleção**: Lidar com a operação de "excluir-coleção", remover todos os dados da coleção +**Verificação de Existência da Coleção**: Validação interna antes de aceitar operações de gravação + +APIs de Operação de Dados (Comportamento Modificado): +**APIs de Gravação**: Validar se a coleção existe antes de aceitar dados, retornar um erro se não existir +**APIs de Consulta**: Retornar resultados vazios para coleções inexistentes sem erro + +### Detalhes de Implementação + +A implementação seguirá os padrões existentes do TrustGraph para integração de serviços e estrutura de comandos de linha de comando. + +#### Exclusão em Cadeia de Coleção + +Quando um usuário inicia a exclusão de uma coleção por meio do serviço de bibliotecário: + +1. **Validação de Metadados**: Verificar se a coleção existe e se o usuário tem permissão para excluí-la +2. **Propagação para o Armazenamento**: O bibliotecário coordena a exclusão em todos os escritores de armazenamento: + Escritor de armazenamento vetorial: Remover incorporações e índices de vetor para o usuário e a coleção + Escritor de armazenamento de objetos: Remover documentos e arquivos para o usuário e a coleção + Escritor de triple store: Remover dados de grafo e triples para o usuário e a coleção +3. **Limpeza de Metadados**: Remover o registro de metadados da coleção do Cassandra +4. **Tratamento de Erros**: Se alguma exclusão de armazenamento falhar, manter a consistência por meio de mecanismos de reversão ou repetição + +#### Interface de Gerenciamento de Coleção + +**⚠️ ABORDAGEM ANTIGA - SUBSTITUÍDA POR PADRÃO BASEADO EM CONFIGURAÇÃO** + +A arquitetura baseada em fila descrita abaixo foi substituída por uma abordagem baseada em configuração usando `CollectionConfigHandler`. Todos os backends de armazenamento agora recebem atualizações de coleção por meio de mensagens de configuração em vez de filas de gerenciamento dedicadas. + +~~Todos os escritores de armazenamento implementam uma interface de gerenciamento de coleção padronizada com um esquema comum:~~ + +~~**Esquema de Mensagem (`StorageManagementRequest`):**~~ +```json +{ + "operation": "create-collection" | "delete-collection", + "user": "user123", + "collection": "documents-2024" +} +``` + +~~**Arquitetura de Filas:**~~ +~~**Fila de Gerenciamento de Vetores** (`vector-storage-management`): Armazenamentos de vetores/embeddings~~ +~~**Fila de Gerenciamento de Objetos** (`object-storage-management`): Armazenamentos de objetos/documentos~~ +~~**Fila de Gerenciamento de Triplas** (`triples-storage-management`): Armazenamentos de grafos/RDF~~ +~~**Fila de Resposta de Armazenamento** (`storage-management-response`): Todas as respostas são enviadas aqui~~ + +**Implementação Atual:** + +Todos os backends de armazenamento agora usam `CollectionConfigHandler`: +**Integração de Configuração Push**: Os serviços de armazenamento se registram para notificações de configuração push +**Sincronização Automática**: Coleções criadas/excluídas com base em alterações de configuração +**Modelo Declarativo**: Coleções definidas no serviço de configuração, os backends sincronizam para corresponder +**Sem Requisição/Resposta**: Elimina a sobrecarga de coordenação e o rastreamento de respostas +**Rastreamento do Estado da Coleção**: Mantido via cache `known_collections` +**Operações Idempotentes**: É seguro processar a mesma configuração várias vezes + +Cada backend de armazenamento implementa: +`create_collection(user: str, collection: str, metadata: dict)` - Criar estruturas de coleção +`delete_collection(user: str, collection: str)` - Remover todos os dados da coleção +`collection_exists(user: str, collection: str) -> bool` - Validar antes de gravar + +#### Refatoração do Armazenamento de Triplas Cassandra + +Como parte desta implementação, o armazenamento de triplas Cassandra será refatorado de um modelo de tabela por coleção para um modelo de tabela unificada: + +**Arquitetura Atual:** +Keyspace por usuário, tabela separada por coleção +Esquema: `(s, p, o)` com `PRIMARY KEY (s, p, o)` +Nomes de tabela: coleções de usuários se tornam tabelas Cassandra separadas + +**Nova Arquitetura:** +Keyspace por usuário, tabela única "triples" para todas as coleções +Esquema: `(collection, s, p, o)` com `PRIMARY KEY (collection, s, p, o)` +Isolamento de coleção por meio de particionamento de coleção + +**Alterações Necessárias:** + +1. **Refatoração da Classe TrustGraph** (`trustgraph/direct/cassandra.py`): + Remover o parâmetro `table` do construtor, usar a tabela "triples" fixa + Adicionar o parâmetro `collection` a todos os métodos + Atualizar o esquema para incluir a coleção como a primeira coluna + **Atualizações de Índice**: Novos índices serão criados para suportar todos os 8 padrões de consulta: + Índice em `(s)` para consultas baseadas em sujeito + Índice em `(p)` para consultas baseadas em predicado + Índice em `(o)` para consultas baseadas em objeto + Observação: O Cassandra não suporta índices secundários multi-coluna, portanto, estes são índices de coluna única + + **Desempenho do Padrão de Consulta:** + ✅ `get_all()` - varredura de partição em `collection` + ✅ `get_s(s)` - usa a chave primária de forma eficiente (`collection, s`) + ✅ `get_p(p)` - usa `idx_p` com filtragem `collection` + ✅ `get_o(o)` - usa `idx_o` com filtragem `collection` + ✅ `get_sp(s, p)` - usa a chave primária de forma eficiente (`collection, s, p`) + ⚠️ `get_po(p, o)` - requer `ALLOW FILTERING` (usa `idx_p` ou `idx_o` mais filtragem) + ✅ `get_os(o, s)` - usa `idx_o` com filtragem adicional em `s` + ✅ `get_spo(s, p, o)` - usa toda a chave primária de forma eficiente + + **Observação sobre ALLOW FILTERING**: O padrão de consulta `get_po` requer `ALLOW FILTERING`, pois precisa tanto de restrições de predicado quanto de objeto sem um índice composto adequado. Isso é aceitável, pois este padrão de consulta é menos comum do que as consultas baseadas em sujeito no uso típico de armazenamentos de triplas. + +2. **Atualizações do Gravador de Armazenamento** (`trustgraph/storage/triples/cassandra/write.py`): + Manter uma única conexão TrustGraph por usuário em vez de por (usuário, coleção) + Passar a coleção para as operações de inserção + Melhor utilização de recursos com menos conexões + +3. **Atualizações do Serviço de Consulta** (`trustgraph/query/triples/cassandra/service.py`): + Uma única conexão TrustGraph por usuário + Passar a coleção para todas as operações de consulta + Manter a mesma lógica de consulta com o parâmetro de coleção + +**Benefícios:** +**Exclusão Simplificada de Coleções**: Excluir usando a chave de partição `collection` em todas as 4 tabelas +**Eficiência de Recursos**: Menos conexões de banco de dados e objetos de tabela +**Operações entre Coleções**: Mais fácil de implementar operações que abrangem várias coleções +**Arquitetura Consistente**: Alinha-se com a abordagem unificada de metadados de coleção +**Validação de Coleção**: Fácil de verificar a existência da coleção via tabela `triples_collection` + +As operações de coleção serão atômicas sempre que possível e fornecerão tratamento de erros e validação apropriados. + +## Considerações de Segurança + +As operações de gerenciamento de coleção requerem autorização apropriada para evitar acesso ou exclusão não autorizados de coleções. O controle de acesso estará alinhado com os modelos de segurança TrustGraph existentes. + +## Considerações de Desempenho + +As operações de listagem de coleções podem precisar de paginação para ambientes com um grande número de coleções. As consultas de metadados devem ser otimizadas para padrões de filtragem comuns. + +## Estratégia de Testes + +Os testes abrangentes cobrirão: +Fluxo de trabalho de criação de coleção de ponta a ponta +Sincronização do armazenamento de back-end +Validação de gravação para coleções inexistentes +Tratamento de consultas para coleções inexistentes +Exclusão de coleção em cascata em todos os armazenamentos +Cenários de tratamento de erros e recuperação +Testes unitários para cada armazenamento de back-end +Testes de integração para operações entre armazenamentos + +## Status da Implementação + +### ✅ Componentes Concluídos + +1. **Serviço de Gerenciamento de Coleção Librarian** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`) + Operações CRUD de metadados de coleção (listagem, atualização, exclusão) + Integração da tabela de metadados de coleção do Cassandra via `LibraryTableStore` + Coordenação da exclusão de coleção em cascata em todos os tipos de armazenamento + Tratamento de solicitações/respostas assíncronas com gerenciamento de erros adequado + +2. **Esquema de Metadados de Coleção** (`trustgraph-base/trustgraph/schema/services/collection.py`) + Esquemas `CollectionManagementRequest` e `CollectionManagementResponse` + Esquema `CollectionMetadata` para registros de coleção + Definições de tópicos de fila de solicitações/respostas de coleção + +3. **Esquema de Gerenciamento de Armazenamento** (`trustgraph-base/trustgraph/schema/services/storage.py`) + Esquemas `StorageManagementRequest` e `StorageManagementResponse` + Tópicos de fila de gerenciamento de armazenamento definidos + Formato de mensagem para operações de coleção no nível do armazenamento + +4. **Esquema de 4 Tabelas do Cassandra** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`) + Chaves de partição compostas para desempenho da consulta + Tabela `triples_collection` para consultas SPO e rastreamento de exclusão + Exclusão de coleção implementada com o padrão de leitura e exclusão + +### ✅ Migração para Padrão Baseado em Configuração - CONCLUÍDO + +**Todos os armazenamentos de back-end foram migrados do padrão baseado em fila para o padrão baseado em configuração `CollectionConfigHandler`.** + +Migrações concluídas: +✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` + +Todos os backends agora: +Herdam de `CollectionConfigHandler` +Registram-se para notificações de push de configuração via `self.register_config_handler(self.on_collection_config)` +Implementam `create_collection(user, collection, metadata)` e `delete_collection(user, collection)` +Usam `collection_exists(user, collection)` para validar antes de gravar +Sincronizam automaticamente com as alterações do serviço de configuração + +Infraestrutura baseada em fila herdada removida: +✅ Esquemas `StorageManagementRequest` e `StorageManagementResponse` removidos +✅ Definições de tópicos de fila de gerenciamento de armazenamento removidas +✅ Consumidor/produtor de gerenciamento de armazenamento removido de todos os backends +✅ Manipuladores `on_storage_management` removidos de todos os backends + diff --git a/docs/tech-specs/collection-management.ru.md b/docs/tech-specs/collection-management.ru.md new file mode 100644 index 00000000..4ab4077a --- /dev/null +++ b/docs/tech-specs/collection-management.ru.md @@ -0,0 +1,403 @@ +# Техническая спецификация управления коллекциями + +## Обзор + +Эта спецификация описывает возможности управления коллекциями для TrustGraph, требуя явного создания коллекций и обеспечивая прямой контроль над жизненным циклом коллекций. Коллекции должны быть явно созданы перед использованием, что обеспечивает надлежащую синхронизацию между метаданными библиотекаря и всеми хранилищами. Эта функция поддерживает четыре основных сценария использования: + +1. **Создание коллекции**: Явно создавайте коллекции перед сохранением данных. +2. **Перечисление коллекций**: Просматривайте все существующие коллекции в системе. +3. **Управление метаданными коллекции**: Обновляйте имена, описания и теги коллекций. +4. **Удаление коллекции**: Удаляйте коллекции и связанные с ними данные во всех типах хранилищ. + +## Цели + +**Явное создание коллекции**: Требуйте, чтобы коллекции создавались перед сохранением данных. +**Синхронизация хранилищ**: Обеспечьте наличие коллекций во всех хранилищах (векторах, объектах, тройках). +**Видимость коллекций**: Предоставьте пользователям возможность перечислять и просматривать все коллекции в их среде. +**Очистка коллекций**: Разрешите удаление коллекций, которые больше не нужны. +**Организация коллекций**: Поддержка меток и тегов для лучшего отслеживания и обнаружения коллекций. +**Управление метаданными**: Связывайте значимые метаданные с коллекциями для обеспечения оперативной ясности. +**Обнаружение коллекций**: Облегчите поиск конкретных коллекций с помощью фильтрации и поиска. +**Оперативная прозрачность**: Обеспечьте четкую видимость жизненного цикла и использования коллекций. +**Управление ресурсами**: Позвольте очищать неиспользуемые коллекции для оптимизации использования ресурсов. +**Целостность данных**: Предотвратите появление "сиротских" коллекций в хранилище без отслеживания метаданных. + +## Предыстория + +Ранее коллекции в TrustGraph создавались неявно во время операций загрузки данных, что приводило к проблемам синхронизации, когда коллекции могли существовать в хранилищах без соответствующих метаданных в библиотекаре. Это создавало проблемы управления и потенциальные "сиротские" данные. + +Модель явного создания коллекций решает эти проблемы следующим образом: +Требует создания коллекций перед использованием через `tg-set-collection`. +Передает информацию о создании коллекции во все хранилища. +Поддерживает синхронизированное состояние между метаданными библиотекаря и хранилищем. +Предотвращает запись в несуществующие коллекции. +Обеспечивает четкое управление жизненным циклом коллекций. + +Эта спецификация определяет модель явного управления коллекциями. Требуя явного создания коллекций, TrustGraph обеспечивает: +Отслеживание коллекций в метаданных библиотекаря с момента создания. +Знание всеми хранилищами о коллекциях до получения данных. +Отсутствие "сиротских" коллекций в хранилище. +Четкую оперативную видимость и контроль над жизненным циклом коллекций. +Последовательную обработку ошибок при выполнении операций, ссылающихся на несуществующие коллекции. + +## Технический дизайн + +### Архитектура + +Система управления коллекциями будет реализована в существующей инфраструктуре TrustGraph: + +1. **Интеграция с сервисом библиотекаря** + Операции управления коллекциями будут добавлены в существующий сервис библиотекаря. + Не требуется новый сервис - используется существующая аутентификация и модели доступа. + Обрабатывает перечисление коллекций, удаление и управление метаданными. + + Модуль: trustgraph-librarian + +2. **Таблица метаданных коллекций Cassandra** + Новая таблица в существующем пространстве ключей библиотекаря. + Хранит метаданные коллекций с доступом, специфичным для пользователя. + Первичный ключ: (user_id, collection_id) для обеспечения правильной многопользовательской среды. + + Модуль: trustgraph-librarian + +3. **CLI для управления коллекциями** + Интерфейс командной строки для операций с коллекциями. + Предоставляет команды для перечисления, удаления, добавления меток и тегов. + Интегрируется с существующей инфраструктурой CLI. + + Модуль: trustgraph-cli + +### Модели данных + +#### Таблица метаданных коллекций Cassandra + +Метаданные коллекций будут храниться в структурированной таблице Cassandra в пространстве ключей библиотекаря: + +```sql +CREATE TABLE collections ( + user text, + collection text, + name text, + description text, + tags set, + created_at timestamp, + updated_at timestamp, + PRIMARY KEY (user, collection) +); +``` + +Структура таблицы: +**user** + **collection**: Составной первичный ключ, обеспечивающий изоляцию пользователей +**name**: Человекочитаемое имя коллекции +**description**: Подробное описание назначения коллекции +**tags**: Набор тегов для категоризации и фильтрации +**created_at**: Временная метка создания коллекции +**updated_at**: Временная метка последнего изменения + +Этот подход позволяет: +Управление коллекциями с поддержкой многопользовательского режима и изоляцией пользователей +Эффективный поиск по пользователю и коллекции +Гибкая система тегирования для организации +Отслеживание жизненного цикла для получения оперативной информации + +#### Жизненный цикл коллекции + +Коллекции явно создаются в библиотечнике, прежде чем можно будет выполнять операции с данными: + +1. **Создание коллекции** (Два пути): + + **Путь A: Создание, инициированное пользователем** через `tg-set-collection`: + Пользователь предоставляет идентификатор коллекции, имя, описание и теги + Библиотечник создает запись метаданных в таблице `collections` + Библиотечник отправляет сообщение "create-collection" всем хранилищам данных + Все процессоры хранилищ создают коллекцию и подтверждают успешное выполнение + Коллекция готова для операций с данными + + **Путь B: Автоматическое создание при отправке документа**: + Пользователь отправляет документ, указывающий идентификатор коллекции + Библиотечник проверяет, существует ли коллекция в таблице метаданных + Если коллекция не существует: Библиотечник создает метаданные с настройками по умолчанию (имя = идентификатор коллекции, пустое описание/теги) + Библиотечник отправляет сообщение "create-collection" всем хранилищам данных + Все процессоры хранилищ создают коллекцию и подтверждают успешное выполнение + Обработка документа продолжается после создания коллекции + + Оба пути обеспечивают существование коллекции в метаданных библиотечника И во всех хранилищах данных перед выполнением операций с данными. + +2. **Проверка хранилища**: Операции записи проверяют существование коллекции: + Процессоры хранилищ проверяют состояние коллекции перед принятием записи + Записи в несуществующие коллекции возвращают ошибку + Это предотвращает прямые записи, обходя логику создания коллекции библиотечником + +3. **Поведение при запросах**: Операции запроса корректно обрабатывают несуществующие коллекции: + Запросы к несуществующим коллекциям возвращают пустые результаты + Не возникает ошибок для операций запроса + Позволяет исследовать данные без необходимости существования коллекции + +4. **Обновление метаданных**: Пользователи могут обновлять метаданные коллекции после ее создания: + Обновление имени, описания и тегов через `tg-set-collection` + Обновления применяются только к метаданным библиотечника + Хранилища данных сохраняют коллекцию, но обновления метаданных не распространяются + +5. **Явное удаление**: Пользователи удаляют коллекции через `tg-delete-collection`: + Библиотечник отправляет сообщение "delete-collection" всем хранилищам данных + Ожидает подтверждение от всех процессоров хранилищ + Удаляет запись метаданных библиотечника только после завершения очистки хранилища + Обеспечивает отсутствие "осиротевших" данных в хранилище + +**Ключевой принцип**: Библиотечник является центральной точкой управления созданием коллекций. Независимо от того, инициировано ли это пользовательской командой или отправкой документа, библиотечник обеспечивает правильное отслеживание метаданных и синхронизацию хранилищ данных, прежде чем разрешить операции с данными. + +Требуемые операции: +**Создание коллекции**: Операция пользователя через `tg-set-collection` ИЛИ автоматическое создание при отправке документа +**Обновление метаданных коллекции**: Операция пользователя для изменения имени, описания и тегов +**Удаление коллекции**: Операция пользователя для удаления коллекции и ее данных во всех хранилищах +**Список коллекций**: Операция пользователя для просмотра коллекций с фильтрацией по тегам + +#### Управление коллекциями в нескольких хранилищах + +Коллекции существуют в нескольких хранилищах данных в TrustGraph: +**Векторные хранилища** (Qdrant, Milvus, Pinecone): Хранят вложения и векторные данные +**Объектные хранилища** (Cassandra): Хранят документы и файлы +**Графовые хранилища** (Cassandra, Neo4j, Memgraph, FalkorDB): Хранят данные графов/RDF + +Каждый тип хранилища реализует: +**Отслеживание состояния коллекций**: Поддержание информации о том, какие коллекции существуют. +**Создание коллекций**: Прием и обработка операций "создать коллекцию". +**Проверка существования коллекций**: Проверка существования коллекции перед записью данных. +**Удаление коллекций**: Удаление всех данных для указанной коллекции. + +Сервис библиотекаря координирует операции с коллекциями во всех типах хранилищ, обеспечивая: +Создание коллекций во всех бэкендах перед использованием. +Подтверждение создания всеми бэкендами перед возвратом успеха. +Синхронизированный жизненный цикл коллекций во всех типах хранилища. +Последовательную обработку ошибок, когда коллекции не существуют. + +#### Отслеживание состояния коллекций по типу хранилища + +Каждый бэкенд хранилища отслеживает состояние коллекций по-разному, в зависимости от его возможностей: + +**Triple Store на базе Cassandra:** +Использует существующую таблицу `triples_collection`. +Создает системный маркер-трипл при создании коллекции. +Запрос: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1`. +Эффективная проверка существования коллекции в одной партиции. + +**Векторные хранилища Qdrant/Milvus/Pinecone:** +Нативные API коллекций обеспечивают проверку существования. +Коллекции создаются с правильной конфигурацией векторов. +Метод `collection_exists()` использует API хранилища. +Создание коллекции проверяет требования к размерности. + +**Графовые хранилища Neo4j/Memgraph/FalkorDB:** +Используют узлы `:CollectionMetadata` для отслеживания коллекций. +Свойства узла: `{user, collection, created_at}`. +Запрос: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})`. +Отделены от узлов данных для четкого разделения. +Обеспечивает эффективное перечисление и проверку коллекций. + +**Объектное хранилище на базе Cassandra:** +Использует таблицу метаданных коллекции или маркерные строки. +Аналогичный шаблон, что и для triple store. +Проверяет существование коллекции перед записью документов. + +### API + +API управления коллекциями (Библиотекарь): +**Создание/Обновление коллекции**: Создание новой коллекции или обновление существующих метаданных через `tg-set-collection`. +**Список коллекций**: Получение коллекций для пользователя с необязательной фильтрацией по тегам. +**Удаление коллекции**: Удаление коллекции и связанных данных, распространяясь на все типы хранилищ. + +API управления хранилищем (Все процессоры хранилища): +**Создание коллекции**: Обработка операции "создать коллекцию", создание коллекции в хранилище. +**Удаление коллекции**: Обработка операции "удалить коллекцию", удаление всех данных коллекции. +**Проверка существования коллекции**: Внутренняя проверка перед принятием операций записи. + +API операций с данными (Измененное поведение): +**API записи**: Проверка существования коллекции перед принятием данных, возврат ошибки, если коллекция не существует. +**API запросов**: Возврат пустых результатов для несуществующих коллекций без ошибки. + +### Детали реализации + +Реализация будет следовать существующим шаблонам TrustGraph для интеграции служб и структуры командной строки. + +#### Каскадное удаление коллекций + +Когда пользователь инициирует удаление коллекции через сервис библиотекаря: + +1. **Проверка метаданных**: Проверка существования коллекции и наличие у пользователя разрешения на удаление. +2. **Каскадное удаление в хранилищах**: Библиотекарь координирует удаление во всех хранилищах записи: + Хранилище векторов: Удаление вложений и индексов векторов для пользователя и коллекции. + Объектное хранилище: Удаление документов и файлов для пользователя и коллекции. + Графовое хранилище: Удаление данных графа и триплетов для пользователя и коллекции. +3. **Очистка метаданных**: Удаление записи метаданных коллекции из Cassandra. +4. **Обработка ошибок**: Если удаление в каком-либо хранилище не удалось, поддерживайте согласованность с помощью механизмов отката или повторной попытки. + +#### Интерфейс управления коллекциями + +**⚠️ УСТАРЕВШИЙ ПОДХОД - ЗАМЕЩЕН ШАБЛОНОМ НА ОСНОВЕ КОНФИГУРАЦИИ** + +Архитектура на основе очереди, описанная ниже, была заменена подходом на основе конфигурации с использованием `CollectionConfigHandler`. Все бэкенды хранилищ теперь получают обновления коллекций через сообщения push конфигурации, а не через выделенные очереди управления. + +~~Все хранилища записи реализуют стандартизированный интерфейс управления коллекциями с общей схемой:~~ + +~~**Схема сообщения (`StorageManagementRequest`):**~~ +```json +{ + "operation": "create-collection" | "delete-collection", + "user": "user123", + "collection": "documents-2024" +} +``` + +~~**Архитектура очередей:**~~ +~~**Очередь управления векторными хранилищами** (`vector-storage-management`): векторные/эмбеддинговые хранилища~~ +~~**Очередь управления хранилищами объектов** (`object-storage-management`): хранилища объектов/документов~~ +~~**Очередь управления графовыми хранилищами** (`triples-storage-management`): графовые/RDF хранилища~~ +~~**Очередь обработки ответов хранилища** (`storage-management-response`): все ответы отправляются сюда~~ + +**Текущая реализация:** + +Все бэкенды хранилищ теперь используют `CollectionConfigHandler`: +**Интеграция с системой push-уведомлений конфигурации**: службы хранилищ регистрируются для получения уведомлений об изменениях конфигурации +**Автоматическая синхронизация**: коллекции создаются/удаляются на основе изменений конфигурации +**Декларативная модель**: коллекции определены в службе конфигурации, бэкенды синхронизируются для соответствия +**Отсутствие запросов/ответов**: устраняет накладные расходы на координацию и отслеживание ответов +**Отслеживание состояния коллекций**: поддерживается через кэш `known_collections` +**Идемпотентные операции**: безопасно обрабатывать одну и ту же конфигурацию несколько раз + +Каждый бэкенд хранилища реализует: +`create_collection(user: str, collection: str, metadata: dict)` - Создание структур коллекций +`delete_collection(user: str, collection: str)` - Удаление всех данных коллекций +`collection_exists(user: str, collection: str) -> bool` - Проверка перед записью + +#### Рефакторинг графового хранилища Cassandra + +В рамках этой реализации графовое хранилище Cassandra будет переработано с модели "таблица на коллекцию" на унифицированную модель "одна таблица": + +**Текущая архитектура:** +Keyspace на пользователя, отдельная таблица на коллекцию +Схема: `(s, p, o)` с `PRIMARY KEY (s, p, o)` +Имена таблиц: коллекции пользователя становятся отдельными таблицами Cassandra + +**Новая архитектура:** +Keyspace на пользователя, одна таблица "triples" для всех коллекций +Схема: `(collection, s, p, o)` с `PRIMARY KEY (collection, s, p, o)` +Изоляция коллекций через партиционирование коллекций + +**Необходимые изменения:** + +1. **Рефакторинг класса TrustGraph** (`trustgraph/direct/cassandra.py`): + Удалить параметр `table` из конструктора, использовать фиксированную таблицу "triples" + Добавить параметр `collection` ко всем методам + Обновить схему для включения коллекции в качестве первого столбца + **Обновления индексов**: Будут созданы новые индексы для поддержки всех 8 шаблонов запросов: + Индекс на `(s)` для запросов на основе субъекта + Индекс на `(p)` для запросов на основе предиката + Индекс на `(o)` для запросов на основе объекта + Обратите внимание: Cassandra не поддерживает многоколоночные вторичные индексы, поэтому это одноколоночные индексы + + **Производительность шаблонов запросов**: + ✅ `get_all()` - сканирование раздела на `collection` + ✅ `get_s(s)` - эффективно использует первичный ключ (`collection, s`) + ✅ `get_p(p)` - использует `idx_p` с фильтрацией `collection` + ✅ `get_o(o)` - использует `idx_o` с фильтрацией `collection` + ✅ `get_sp(s, p)` - эффективно использует первичный ключ (`collection, s, p`) + ⚠️ `get_po(p, o)` - требует `ALLOW FILTERING` (использует либо `idx_p`, либо `idx_o` плюс фильтрацию) + ✅ `get_os(o, s)` - использует `idx_o` с дополнительной фильтрацией на `s` + ✅ `get_spo(s, p, o)` - эффективно использует полный первичный ключ + + **Примечание об ALLOW FILTERING**: Шаблон запроса `get_po` требует `ALLOW FILTERING`, поскольку ему необходимы ограничения как предиката, так и объекта без подходящего составного индекса. Это допустимо, поскольку этот шаблон запроса менее распространен, чем запросы на основе субъекта, в типичном использовании хранилища тройных данных. + +2. **Обновления модуля записи данных** (`trustgraph/storage/triples/cassandra/write.py`): + Поддерживать одно соединение TrustGraph на пользователя вместо одного соединения на (пользователь, коллекция) + Передавать коллекцию в операции вставки + Улучшенное использование ресурсов за счет меньшего количества соединений + +3. **Обновления сервиса запросов** (`trustgraph/query/triples/cassandra/service.py`): + Одно соединение TrustGraph на пользователя + Передавать коллекцию во все операции запросов + Сохранять ту же логику запросов с параметром коллекции + +**Преимущества:** +**Упрощенное удаление коллекций**: Удаление с использованием ключа раздела `collection` во всех 4 таблицах +**Эффективность использования ресурсов**: Меньшее количество соединений с базой данных и объектов таблиц +**Операции, охватывающие несколько коллекций**: Легче реализовать операции, охватывающие несколько коллекций +**Согласованная архитектура**: Соответствует унифицированному подходу к метаданным коллекций +**Проверка коллекций**: Легко проверить существование коллекции через таблицу `triples_collection` + +Операции с коллекциями будут выполняться атомарно, где это возможно, и обеспечивать соответствующую обработку ошибок и проверку. + +## Вопросы безопасности + +Управление коллекциями требует соответствующей авторизации для предотвращения несанкционированного доступа или удаления коллекций. Контроль доступа будет соответствовать существующим моделям безопасности TrustGraph. + +## Вопросы производительности + +Операции перечисления коллекций могут требовать постраничной разбивки для сред с большим количеством коллекций. Запросы метаданных должны быть оптимизированы для распространенных шаблонов фильтрации. + +## Стратегия тестирования + +Комплексное тестирование будет охватывать: +Рабочий процесс создания коллекции от начала до конца +Синхронизация с хранилищем +Проверка при записи для несуществующих коллекций +Обработка запросов для несуществующих коллекций +Каскадное удаление коллекций во всех хранилищах +Обработка ошибок и сценарии восстановления +Юнит-тесты для каждого хранилища +Интеграционные тесты для операций между хранилищами + +## Статус реализации + +### ✅ Завершенные компоненты + +1. **Сервис управления коллекциями Librarian** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`) + Операции CRUD (создание, чтение, обновление, удаление) метаданных коллекции + Интеграция с таблицей метаданных коллекций Cassandra через `LibraryTableStore` + Координация каскадного удаления коллекций во всех типах хранилищ + Асинхронная обработка запросов/ответов с надлежащим управлением ошибками + +2. **Схема метаданных коллекции** (`trustgraph-base/trustgraph/schema/services/collection.py`) + Схемы `CollectionManagementRequest` и `CollectionManagementResponse` + Схема `CollectionMetadata` для записей коллекций + Определения тем очередей для запросов/ответов коллекции + +3. **Схема управления хранилищем** (`trustgraph-base/trustgraph/schema/services/storage.py`) + Схемы `StorageManagementRequest` и `StorageManagementResponse` + Определены темы очередей для управления хранилищем + Формат сообщения для операций с коллекциями на уровне хранилища + +4. **Схема Cassandra для 4 таблиц** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`) + Составные ключи разделов для повышения производительности запросов + Таблица `triples_collection` для запросов SPO и отслеживания удаления + Реализовано удаление коллекций с использованием шаблона "чтение-затем-удаление" + +### ✅ Миграция на конфигурационно-ориентированный шаблон - ЗАВЕРШЕНО + +**Все хранилища были перенесены из шаблона на основе очереди на конфигурационно-ориентированный шаблон `CollectionConfigHandler`.** + +Выполненные миграции: +✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` + +Теперь все хранилища: +Наследуют от `CollectionConfigHandler` +Регистрируются для получения уведомлений об изменениях конфигурации через `self.register_config_handler(self.on_collection_config)` +Реализуют `create_collection(user, collection, metadata)` и `delete_collection(user, collection)` +Используют `collection_exists(user, collection)` для проверки перед записью +Автоматически синхронизируются с изменениями сервиса конфигурации + +Устаревшая инфраструктура на основе очереди удалена: +✅ Удалены схемы `StorageManagementRequest` и `StorageManagementResponse` +✅ Удалены определения тем управления хранилищем +✅ Удален потребитель/производитель очереди управления хранилищем из всех хранилищ +✅ Удалены обработчики `on_storage_management` из всех хранилищ + diff --git a/docs/tech-specs/collection-management.sw.md b/docs/tech-specs/collection-management.sw.md new file mode 100644 index 00000000..f97372e6 --- /dev/null +++ b/docs/tech-specs/collection-management.sw.md @@ -0,0 +1,403 @@ +# Maelekezo ya Ufundi ya Usimamizi wa Mkusanyiko + +## Muhtasari + +Maelekezo haya yanaelezea uwezo wa usimamizi wa mkusanyiko kwa TrustGraph, ambayo yanahitaji uundaji wa mkusanyiko unaoonekana na yanatoa udhibiti wa moja kwa moja wa mzunguko wa maisha wa mkusanyiko. Mkusanyiko lazima uundwe kwa uwazi kabla ya kutumika, kuhakikisha usawazishaji sahihi kati ya metadata ya msimamizi na kila mfumo wa kuhifadhi. Kipengele hiki kinaunga mkazo kwa matumizi manne makuu: + +1. **Uundaji wa Mkusanyiko**: Unda mkusanyiko kwa uwazi kabla ya kuhifadhi data +2. **Orodha ya Mkusanyiko**: Angalia mkusanyiko wote uliopo katika mfumo +3. **Usimamizi wa Metadata ya Mkusanyiko**: Sasisha majina, maelezo, na lebo za mkusanyiko +4. **Ufutaji wa Mkusanyiko**: Ondoa mkusanyiko na data inayohusiana katika aina zote za uhifadhi + +## Lengo + +**Uundaji wa Mkusanyiko unaoonekana**: Hakikisha mkusanyiko uundwe kabla ya data kuweza kuhifadhiwa +**Usawazishaji wa Uhifadhi**: Hakikisha mkusanyiko umezaliwa katika mifumo yote ya uhifadhi (vektali, vitu, triplet) +**Uonevu wa Mkusanyiko**: Wasaidie watumiaji kuorodhesha na kuchunguza mkusanyiko wote katika mazingira yao +**Usafishaji wa Mkusanyiko**: Waruhusu kuondoa mkusanyiko ambao hauhitajiki tena +**Mpangilio wa Mkusanyiko**: Unga lebo na lebo za mada kwa ajili ya ufuatiliaji na ugunduzi bora wa mkusanyiko +**Usimamizi wa Metadata**: Unganisha metadata inayoeleweka na mkusanyiko kwa uwazi wa utendaji +**Ugunduzi wa Mkusanyiko**: Ifanye iwe rahisi zaidi kupata mkusanyiko maalum kupitia utaratibu na utafutaji +**Uwazi wa Utendaji**: Toa uonevu wazi wa mzunguko wa maisha na matumizi ya mkusanyiko +**Usimamizi wa Rasilimali**: Wasaidie kusafisha mkusanyiko usiohitajika ili kuongeza matumizi ya rasilimali +**Uadilifu wa Data**: Zuia mkusanyiko usio na uhusiano katika uhifadhi bila kufuatilia metadata + +## Asili + +Hapo awali, mkusanyiko katika TrustGraph uliundwa kwa njia isiyoonekana wakati wa operesheni za kupakia data, na kusababisha matatizo ya usawazishaji ambapo mkusanyiko ulikuwa na uwezekano wa kuwepo katika mifumo ya uhifadhi bila metadata inayolingana katika msimamizi. Hii ilisababisha changamoto za usimamizi na uwezekano wa data isiyo na uhusiano. + +Mfumo wa uundaji wa mkusanyiko unaoonekana unafanya kazi na masuala haya kwa: +Kuhitaji mkusanyiko uundwe kabla ya kutumika kupitia `tg-set-collection` +Kutangaza uundaji wa mkusanyiko kwa mifumo yote ya uhifadhi +Kuhifadhi hali iliyosawazishwa kati ya metadata ya msimamizi na uhifadhi +Kuzuia uandishi kwenye mkusanyiko usio na uwepo +Kutoa usimamizi wazi wa mzunguko wa maisha wa mkusanyiko + +Maelekezo haya yanafafanua mfumo wa usimamizi wa mkusanyiko unaoonekana. Kwa kuhitaji uundaji wa mkusanyiko unaoonekana, TrustGraph huhakikisha: +Mkusanyiko unafuatiliwa katika metadata ya msimamizi kuanzia uundaji +Mifumo yote ya uhifadhi inajua mkusanyiko kabla ya kupokea data +Hakuna mkusanyiko usio na uhusiano katika uhifadhi +Uwazi wa utendaji na udhibiti wa mzunguko wa maisha wa mkusanyiko +Usimamizi thabiti wa makosa wakati operesheni zinarejelea mkusanyiko usio na uwepo + +## Ubunifu wa Kiufundi + +### Usanifu + +Mfumo wa usimamizi wa mkusanyiko utatekelezwa ndani ya miundombinu iliyopo ya TrustGraph: + +1. **Jumuisha Huduma ya Msimamizi** + Operesheni za usimamizi wa mkusanyiko zitaongezwa kwenye huduma iliyopo ya msimamizi + Huduma mpya haihitajiki - inatumia mitindo iliyopo ya uthibitishaji na ufikiaji + Inashughulikia orodha ya mkusanyiko, kufutwa, na usimamizi wa metadata + + Moduli: trustgraph-librarian + +2. **Jedwali la Metadata ya Mkusanyiko la Cassandra** + Jedwali jipya katika nafasi ya funguo ya msimamizi iliyopo + Inahifadhi metadata ya mkusanyiko na ufikiaji wa mtumiaji + Ufunguo mkuu: (user_id, collection_id) kwa usawazishaji sahihi wa wateja wengi + + Moduli: trustgraph-librarian + +3. **Kifaa cha Amri cha Usimamizi wa Mkusanyiko** + Kiwao cha amri kwa operesheni za mkusanyiko + Inatoa orodha, kufuta, lebo, na amri za usimamizi wa lebo + Inajumuisha na mfumo uliopo wa kifaa cha amri + + Moduli: trustgraph-cli + +### Mifano ya Data + +#### Jedwali la Metadata ya Mkusanyiko la Cassandra + +Metadata ya mkusanyiko itahifadhiwa katika jedwali lililopangwa la Cassandra katika nafasi ya funguo ya msimamizi: + +```sql +CREATE TABLE collections ( + user text, + collection text, + name text, + description text, + tags set, + created_at timestamp, + updated_at timestamp, + PRIMARY KEY (user, collection) +); +``` + +Muundo wa jedwali: +**user** + **collection**: Ufunguo mkuu unaojumuisha unaohakikisha kutenganishwa kwa watumiaji +**name**: Jina la mkusanyiko linaloweza kusomwa na binadamu +**description**: Maelezo ya kina ya madhumuni ya mkusanyiko +**tags**: Kundi la lebo kwa ajili ya uainishaji na kuchujwa +**created_at**: Alama ya muda ya uundaji wa mkusanyiko +**updated_at**: Alama ya muda ya mabadiliko ya mwisho + +Mbinu hii inaruhusu: +Usimamizi wa mkusanyiko wa wateja wengi pamoja na kutenganishwa kwa watumiaji +Ufuatiliaji wa haraka kwa mtumiaji na mkusanyiko +Mfumo wa lebo unaobadilika kwa ajili ya upangaji +Ufuatiliaji wa mzunguko wa maisha kwa ajili ya ufahamu wa utendaji + +#### Mzunguko wa Maisha wa Mkusanyiko + +Mkusanyiko huundwa wazi katika mfumo wa usimamizi kabla ya shughuli za data zinaweza kuendelea: + +1. **Uundaji wa Mkusanyiko** (Njia Mbili): + + **Njia A: Uundaji unaoanzishwa na Mtumiaji** kupitia `tg-set-collection`: + Mtumiaji hutoa kitambulisho cha mkusanyiko, jina, maelezo, na lebo + Mfumo wa usimamizi huunda rekodi ya metadata katika meza ya `collections` + Mfumo wa usimamizi hutuma "unda-mkusanyiko" kwa kila mfumo wa kuhifadhi + Mifumo yote ya kuhifadhi huunda mkusanyiko na kuthibitisha mafanikio + Mkusanyiko sasa uko tayari kwa shughuli za data + + **Njia B: Uundaji Otomatiki wakati wa Uwasilishaji wa Hati**: + Mtumiaji huwasilisha hati inayobainisha kitambulisho cha mkusanyiko + Mfumo wa usimamizi huhakikisha ikiwa mkusanyiko umejumuishwa katika meza ya metadata + Ikiwa haujumuishwa: Mfumo wa usimamizi huunda metadata na mipangilio chache (jina=kitambulisho_cha_mkusanyiko, maelezo/lebo tupu) + Mfumo wa usimamizi hutuma "unda-mkusanyiko" kwa kila mfumo wa kuhifadhi + Mifumo yote ya kuhifadhi huunda mkusanyiko na kuthibitisha mafanikio + Ufuatiliaji wa hati unaendelea na mkusanyiko sasa umeanzishwa + + Njia zote mbili zinahakikisha kuwa mkusanyiko umejumuishwa katika metadata ya mfumo wa usimamizi NA katika mifumo yote ya kuhifadhi kabla ya shughuli za data. + +2. **Uthibitisho wa Uhifadhi**: Shughuli za kuandika zinathibitisha kuwa mkusanyiko umejumuishwa: + Mifumo ya kuhifadhi huhakikisha hali ya mkusanyiko kabla ya kukubali kuandika + Kuandika kwa mkusanyiko usiojumuishwa kunarudisha kosa + Hii inazuia kuandika moja kwa moja ambayo yanaweza kuepuka mantiki ya uundaji wa mkusanyiko ya mfumo wa usimamizi + +3. **Tabia ya Ufuatiliaji**: Shughuli za kufuatilia hushughulikia mkusanyiko usiojumuishwa kwa utulivu: + Ufuatiliaji kwa mkusanyiko usiojumuishwa hurudisha matokeo tupu + Hakuna kosa linalorushwa kwa shughuli za kufuatilia + Inaruhusu uchunguzi bila kuhitaji mkusanyiko kuwepo + +4. **Sasisho za Metadata**: Watumiaji wanaweza kusasisha metadata ya mkusanyiko baada ya uundaji: + Sasisha jina, maelezo, na lebo kupitia `tg-set-collection` + Sasisho hutumika kwa metadata ya mfumo wa usimamizi pekee + Mifumo ya kuhifadhi yanaendelea kuweka mkusanyiko lakini sasisho za metadata hazisambazwi + +5. **Ufutaji Wazi**: Watumiaji huondoa mkusanyiko kupitia `tg-delete-collection`: + Mfumo wa usimamizi hutuma "ondoa-mkusanyiko" kwa kila mfumo wa kuhifadhi + Inasubiri uthibitisho kutoka kwa mifumo yote ya kuhifadhi + Huondoa rekodi ya metadata ya mfumo wa usimamizi tu baada ya kusafishwa kwa uhifadhi kukamilika + Inahakikisha hakuna data iliyoachwa katika uhifadhi + +**Kanuni Muhimu**: Mfumo wa usimamizi ndio sehemu pekee ya udhibiti kwa uundaji wa mkusanyiko. Iwe iliyoanzishwa na amri ya mtumiaji au uwasilishaji wa hati, mfumo wa usimamizi huhakikisha ufuatiliaji sahihi wa metadata na usawazishaji wa mfumo wa kuhifadhi kabla ya kuruhusu shughuli za data. + +Shughuli zinazohitajika: +**Unda Mkusanyiko**: Shughuli ya mtumiaji kupitia `tg-set-collection` AU otomatiki wakati wa uwasilishaji wa hati +**Sasisha Metadata ya Mkusanyiko**: Shughuli ya mtumiaji ili kurekebisha jina, maelezo, na lebo +**Ondoa Mkusanyiko**: Shughuli ya mtumiaji ili kuondoa mkusanyiko na data yake katika maduka yote +**Orodha ya Mkusanyiko**: Shughuli ya mtumiaji ili kuona mkusanyiko pamoja na kuchujwa kwa lebo + +#### Usimamizi wa Mkusanyiko wa Maduka Mengi + +Mkusanyiko huwepo katika mifumo tofauti ya kuhifadhi katika TrustGraph: +**Maduka ya Vifaa** (Qdrant, Milvus, Pinecone): Kuhifadhi vifaa na data ya vifaa +**Maduka ya Vitu** (Cassandra): Kuhifadhi hati na data ya faili +**Maduka ya Vitatu** (Cassandra, Neo4j, Memgraph, FalkorDB): Kuhifadhi data ya grafu/RDF + +Kila aina ya duka inatekeleza: +**Ufuatiliaji wa Hali ya Mkusanyiko**: Kuhifadhi habari kuhusu makusanyiko ambayo yamepo. +**Uundaji wa Mkusanyiko**: Kukubali na kuchakata "unda-mkusanyiko" shughuli. +**Uthibitisho wa Mkusanyiko**: Angalia ikiwa mkusanyiko unapatikana kabla ya kukubali uandikaji. +**Ufutaji wa Mkusanyiko**: Ondoa data yote kwa mkusanyiko uliotajwa. + +Huduma ya mhakimishi inaangazia shughuli za mkusanyiko katika aina zote za kuhifadhi, kuhakikisha: +Makusanyiko yanaundwa katika mifumo yote ya nyuma kabla ya matumizi. +Mifumo yote ya nyuma inaonyesha uundaji kabla ya kurejesha mafanikio. +Mzunguko wa mkusanyiko umeunganishwa katika aina tofauti za uhifadhi. +Usimamizi thabiti wa makosa wakati makusanyiko hayapo. + +#### Ufuatiliaji wa Hali ya Mkusanyiko kwa Aina ya Uhifadhi + +Kila mfumo wa nyuma wa uhifadhi unafuatilia hali ya mkusanyiko tofauti kulingana na uwezo wake: + +**Duka la Maneno la Cassandra:** +Hutumia meza iliyopo `triples_collection`. +Huunda alama ya mfumo wakati mkusanyiko unaundwa. +Uulizo: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1`. +Uchunguzi wa sehemu moja kwa uwepo wa mkusanyiko. + +**Vifaa vya Vector vya Qdrant/Milvus/Pinecone:** +API za asili za mkusanyiko hutoa uchunguzi wa uwepo. +Makusanyiko yanaundwa na usanidi sahihi wa vector. +Njia `collection_exists()` hutumia API ya uhifadhi. +Uundaji wa mkusanyiko unafanya uthibitisho wa mahitaji ya kipimo. + +**Vifaa vya Grafu vya Neo4j/Memgraph/FalkorDB:** +Hutumia nodi `:CollectionMetadata` kufuatilia makusanyiko. +Vipengele vya nodi: `{user, collection, created_at}`. +Uulizo: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})`. +Tofauti na nodi za data kwa kutenganisha vizuri. +Inaruhusu orodha na uthibitisho wa mkusanyiko kuwa rahisi. + +**Duka la Vitu la Cassandra:** +Hutumia meza ya metadata ya mkusanyiko au mistari ya alama. +Mfano sawa na duka la maneno. +Inathibitisha mkusanyiko kabla ya uandikaji wa hati. + +### API + +API za Usimamizi wa Mkusanyiko (Mhakimishi): +**Unda/Boresha Mkusanyiko**: Unda mkusanyiko mpya au boresha metadata iliyopo kupitia `tg-set-collection`. +**Orodha ya Makusanyiko**: Pata makusanyiko kwa mtumiaji na uchujaji wa tag wa hiari. +**Futa Mkusanyiko**: Ondoa mkusanyiko na data inayohusiana, na kuenea kwa aina zote za kuhifadhi. + +API za Usimamizi wa Uhifadhi (Wote Wasindikaji wa Uhifadhi): +**Unda Mkusanyiko**: Shughuli ya "unda-mkusanyiko", weka mkusanyiko katika uhifadhi. +**Futa Mkusanyiko**: Shughuli ya "futa-mkusanyiko", ondoa data yote ya mkusanyiko. +**Angalia Ikiwa Mkusanyiko Upo**: Uthibitisho wa ndani kabla ya kukubali shughuli za uandikaji. + +API za Uendeshaji wa Data (Tabia Imebadilishwa): +**API za Uandikaji**: Thibitisha kuwa mkusanyiko unapatikana kabla ya kukubali data, na uweke makosa ikiwa haipo. +**API za Uulizo**: Rejesha matokeo tupu kwa makusanyiko ambayo hayapo bila makosa. + +### Maelezo ya Utendaji + +Utendaji utafuata mifumo iliyopo ya TrustGraph kwa ujumuishaji wa huduma na muundo wa amri ya CLI. + +#### Ufufuo wa Ufufuo wa Mkusanyiko + +Wakati mtumiaji anaanzisha ufutaji wa mkusanyiko kupitia huduma ya mhakimishi: + +1. **Uthibitisho wa Metadata**: Thibitisha kuwa mkusanyiko unapatikana na mtumiaji ana ruhusa ya kufuta. +2. **Ufufuo wa Duka**: Mhakimishi inaangazia ufutaji katika waandishi wote wa duka: + Mwandishi wa duka la vector: Ondoa embeddings na fahirisi za vector kwa mtumiaji na mkusanyiko. + Mwandishi wa duka la kitu: Ondoa hati na faili kwa mtumiaji na mkusanyiko. + Mwandishi wa duka la maneno: Ondoa data ya grafu na maneno kwa mtumiaji na mkusanyiko. +3. **Usafishaji wa Metadata**: Ondoa rekodi ya metadata ya mkusanyiko kutoka Cassandra. +4. **Usimamizi wa Makosa**: Ikiwa ufutaji wowote wa duka hufeli, dhibiti uthabiti kupitia utaratibu wa kurejesha au kujaribu tena. + +#### Kiolesura cha Usimamizi wa Mkusanyiko + +**⚠️ MFUMO WA KALE - IMEBADILISHWA NA MFUMO WA MSINGI WA MSINGI** + +Arkitektura iliyoelezwa ya msingi ya folyo imebadilishwa na mbinu iliyosimama na usanidi inayotumia `CollectionConfigHandler`. Mifumo yote ya nyuma ya uhifadhi sasa hupokea sasisho za mkusanyiko kupitia ujumbe wa kushinikiza usanidi badala ya folyo maalum za usimamizi. + +~~Wote waandishi wa duka inatekeleza kiolesura cha kawaida cha usimamizi wa mkusanyiko na schema ya kawaida:~~ + +~~**Schema ya Ujumbe (`StorageManagementRequest`):**~~ +```json +{ + "operation": "create-collection" | "delete-collection", + "user": "user123", + "collection": "documents-2024" +} +``` + +~~**Usawa wa Mifumo:**~~ +~~**Kikao cha Usimamizi wa Hifadhi ya Data (Vector Store)** (`vector-storage-management`): Hifadhi za vector/embedding~~ +~~**Kikao cha Usimamizi wa Hifadhi ya Data (Object Store)** (`object-storage-management`): Hifadhi za data/nyaraka~~ +~~**Kikao cha Usimamizi wa Hifadhi ya Data (Triple Store)** (`triples-storage-management`): Hifadhi za grafu/RDF~~ +~~**Kikao cha Majibu ya Hifadhi ya Data** (`storage-management-response`): Majibu yote hutumwa hapa~~ + +**Utendaji Sasa:** + +Mifumo yote ya hifadhi ya data sasa hutumia `CollectionConfigHandler`: +**Uunganishaji wa Uhamisho wa Config**: Huduma za hifadhi ya data huzungushwa kwa arifa za uhamisho wa config +**Usawajili Otomatiki**: Mkusanyiko huundwa/kufutwa kulingana na mabadiliko ya config +**Mfumo wa Kielelezo:** Mkusanyiko umeinuliwa katika huduma ya config, hifadhi ya data husawazishwa ili kuendana +**Hakuna Ombi/Jibu:** Huondoa gharama ya uratibu na ufuatiliaji wa majibu +**Ufuatiliaji wa Hali ya Mkusanyiko:** Inahifadhiwa kupitia kumbukumbu `known_collections` +**Operesheni za Idempotent:** Ni salama kuchakata config sawa mara nyingi + +Kila mfumo wa hifadhi ya data unatekeleza: +`create_collection(user: str, collection: str, metadata: dict)` - Unda miundo ya mkusanyiko +`delete_collection(user: str, collection: str)` - Ondoa data yote ya mkusanyiko +`collection_exists(user: str, collection: str) -> bool` - Thibitisha kabla ya kuandika + +#### Urekebishaji wa Hifadhi ya Data ya Triple ya Cassandra + +Kama sehemu ya utekelezaji huu, hifadhi ya data ya triple ya Cassandra itarekebishwa kutoka kwa mfumo wa jedwali-kwa-mkusanyiko hadi mfumo wa jedwali lililo na muundo mmoja: + +**Muundo Sasa:** +Keyspace kwa kila mtumiaji, jedwali tofauti kwa kila mkusanyiko +Schema: `(s, p, o)` na `PRIMARY KEY (s, p, o)` +Majina ya jedwali: mkusanyiko wa mtumiaji unakuwa jedwali tofauti za Cassandra + +**Muundo Mpya:** +Keyspace kwa kila mtumiaji, jedwali moja la "triples" kwa mkusanyiko wote +Schema: `(collection, s, p, o)` na `PRIMARY KEY (collection, s, p, o)` +Utengano wa mkusanyiko kupitia ugawaji wa mkusanyiko + +**Mabadiliko Yanayohitajika:** + +1. **Urekebishaji wa Darasa la TrustGraph** (`trustgraph/direct/cassandra.py`): + Ondoa parameter `table` kutoka kwa konstrukata, tumia jedwali "triples" lililo na muundo mmoja + Ongeza parameter `collection` kwa mbinu zote + Sasisha schema ili kujumuisha mkusanyiko kama safu ya kwanza + **Sasisho za Indexi:** Indexi mpya zitaundwa ili kusaidia mifumo yote 8 ya swali: + Indexi kwenye `(s)` kwa maswali yanayohusiana na mada + Indexi kwenye `(p)` kwa maswali yanayohusiana na sifa + Indexi kwenye `(o)` kwa maswali yanayohusiana na kitu + Kumbuka: Cassandra haitumii indexi za sekondari za safu nyingi, kwa hivyo hizi ni indexi za safu moja + + **Utendaji wa Mfumo wa Swali:** + ✅ `get_all()` - skani ya ugawaji kwenye `collection` + ✅ `get_s(s)` - hutumia ufunguo mkuu kwa ufanisi (`collection, s`) + ✅ `get_p(p)` - hutumia `idx_p` na `collection` ya kuchujwa + ✅ `get_o(o)` - hutumia `idx_o` na `collection` ya kuchujwa + ✅ `get_sp(s, p)` - hutumia ufunguo mkuu kwa ufanisi (`collection, s, p`) + ⚠️ `get_po(p, o)` - inahitaji `ALLOW FILTERING` (inatumia ama `idx_p` au `idx_o` pamoja na kuchujwa) + ✅ `get_os(o, s)` - hutumia `idx_o` na kuchujwa cha ziada kwenye `s` + ✅ `get_spo(s, p, o)` - hutumia ufunguo mkuu kwa ufanisi + + **Kumbuka kuhusu ALLOW FILTERING:** Mfumo wa swali `get_po` unahitaji `ALLOW FILTERING` kwa sababu unahitaji sifa na kikomo cha kitu bila indexi ya pamoja inayofaa. Hii inakubalika kwa sababu mfumo huu wa swali ni mdogo kuliko maswali yanayohusiana na mada katika matumizi ya kawaida ya hifadhi ya data ya triple + +2. **Sasisho za Mwandishi wa Hifadhi ya Data** (`trustgraph/storage/triples/cassandra/write.py`): + Dumishe muunganisho mmoja wa TrustGraph kwa kila mtumiaji badala ya kwa kila (mtumiaji, mkusanyiko) + Pasa mkusanyiko kwenye operesheni za kuingiza + Matumizi bora ya rasilimali kwa muunganisho mdogo + +3. **Sasisho za Huduma ya Swali** (`trustgraph/query/triples/cassandra/service.py`): + Muunganisho mmoja wa TrustGraph kwa kila mtumiaji + Pasa mkusanyiko kwa operesheni zote za swali + Dumishe mantiki sawa ya swali na parameter ya mkusanyiko + +**Faida:** +**Uondoo Ulioboreshwa wa Mkusanyiko:** Ondoa kwa kutumia ufunguo wa ugawaji `collection` katika meza zote 4 +**Ufanisi wa Rasilimali:** Muunganisho mdogo wa hifadhi ya data na vitu vya jedwali +**Operesheni za Mkusanyiko Mbalimbali:** Ni rahisi kutekeleza operesheni zinazohusisha mkusanyiko mwingi +**Muundo Uliofanana:** Inalingana na mbinu iliyounganishwa ya metadata ya mkusanyiko +**Uthibitisho wa Mkusanyiko:** Ni rahisi kuangalia uwepo wa mkusanyiko kupitia jedwali `triples_collection` + +Operesheni za ukusanyaji zitakuwa za atomiki ambapo inawezekana na hutoa utunzaji wa makosa unaofaa na uthibitisho. + +## Masuala ya Usalama + +Operesheni za usimamizi wa ukusanyaji zinahitaji idhini inayofaa ili kuzuia ufikiaji usioidhinishwa au kufutwa kwa ukusanyaji. Udhibiti wa ufikiaji utalingana na modeli za usalama za TrustGraph zilizopo. + +## Masuala ya Utendaji + +Operesheni za kuorodhesha ukusanyaji zinaweza kuhitaji upangishaji katika mazingira yenye idadi kubwa ya ukusanyaji. Maswali ya metadata yanapaswa kuboreshwa kwa mifumo ya kawaida ya kuchujwa. + +## Mkakati wa Majaribio + +Majaribio kamili yataangazia: +Mchakato wa kuunda ukusanyaji kutoka mwanzo hadi mwisho +Usawazishaji wa mfumo wa kuhifadhi data +Uthibitisho wa kuandika kwa ukusanyaji usiopo +Usimamizi wa maswali ya ukusanyaji usiopo +Ufutilishaji wa ukusanyaji unaoenea katika maduka yote +Usimamizi wa makosa na hali ya uponyaji +Majaribio ya kitengo kwa kila mfumo wa kuhifadhi data +Majaribio ya ujumuishaji kwa operesheni za duka nyingi + +## Hali ya Utendaji + +### ✅ Vipengele Vilivyokamilika + +1. **Huduma ya Usimamizi wa Ukusanyaji ya Librarian** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`) + Operesheni za CRUD za metadata ya ukusanyaji (orodha, sasisha, futa) + Ujumuishaji wa jedwali la metadata ya ukusanyaji ya Cassandra kupitia `LibraryTableStore` + Uratibu wa kufutiliwa kwa ukusanyaji unaoenea katika aina zote za uhifadhi + Usimamizi wa ombi/jibu lisilo na wakati pamoja na usimamizi wa makosa unaofaa + +2. **Mfumo wa Metadata wa Ukusanyaji** (`trustgraph-base/trustgraph/schema/services/collection.py`) + Mfumo wa `CollectionManagementRequest` na `CollectionManagementResponse` + Mfumo wa `CollectionMetadata` kwa rekodi za ukusanyaji + Ufafanuzi wa mada ya folyo ya ombi/jibu la ukusanyaji + +3. **Mfumo wa Usimamizi wa Uhifadhi** (`trustgraph-base/trustgraph/schema/services/storage.py`) + Mfumo wa `StorageManagementRequest` na `StorageManagementResponse` + Mada za folyo za usimamizi wa uhifadhi zimefafanuliwa + Muundo wa ujumbe kwa operesheni za ukusanyaji za kiwango cha uhifadhi + +4. **Mfumo wa Jedwali la Cassandra 4** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`) + Funguo za sehemu mchanganyiko kwa utendaji wa swali + Jedwali la `triples_collection` kwa maswali ya SPO na kufuatilia kufutiliwa + Ufutilishaji wa ukusanyaji umetekelezwa na mfumo wa kusoma kisha kufuta + +### ✅ Uhamishaji kwa Mfumo Kulingana na Config - UMEKABALIKA + +**Maduka yote ya uhifadhi yamehamishwa kutoka kwa mfumo unaotegemea folyo hadi kwa mfumo unaotegemea config wa `CollectionConfigHandler`.** + +Uhamishaji uliokamilika: +✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` + +Maduka yote sasa: +Yanachukua kutoka `CollectionConfigHandler` +Yamesajiliwa kwa arifa za config inayoboreshwa kupitia `self.register_config_handler(self.on_collection_config)` +Yatekeleza `create_collection(user, collection, metadata)` na `delete_collection(user, collection)` +Yatumie `collection_exists(user, collection)` ili kuthibitisha kabla ya kuandika +Yanasawazishwa kiotomatiki na mabadiliko ya huduma ya config + +Infrastrakturu ya zamani inayotegemea folyo imeondolewa: +✅ Mfumo wa `StorageManagementRequest` na `StorageManagementResponse` umeondolewa +✅ Ufafanuzi wa mada za usimamizi wa uhifadhi umeondolewa +✅ Mtumiaji/mtayarishaji wa folyo kutoka kwa maduka yote umeondolewa +✅ Wasimamizi wa `on_storage_management` kutoka kwa maduka yote umeondolewa + diff --git a/docs/tech-specs/collection-management.tr.md b/docs/tech-specs/collection-management.tr.md new file mode 100644 index 00000000..c5b0d69a --- /dev/null +++ b/docs/tech-specs/collection-management.tr.md @@ -0,0 +1,403 @@ +# Koleksiyon Yönetimi Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph için koleksiyon yönetimi yeteneklerini tanımlar ve açık koleksiyon oluşturulmasını gerektirir ve koleksiyon yaşam döngüsü üzerinde doğrudan kontrol sağlar. Koleksiyonlar, uygun veri ambarı ve tüm depolama arka uçları arasındaki senkronizasyonu sağlamak için kullanmadan önce açıkça oluşturulmalıdır. Bu özellik, dört birincil kullanım senaryosunu destekler: + +1. **Koleksiyon Oluşturma**: Veri depolamadan önce koleksiyonları açıkça oluşturun +2. **Koleksiyon Listeleme**: Sistemdeki mevcut tüm koleksiyonları görüntüleyin +3. **Koleksiyon Meta Veri Yönetimi**: Koleksiyon adlarını, açıklamalarını ve etiketlerini güncelleyin +4. **Koleksiyon Silme**: Koleksiyonları ve bunlara bağlı verileri tüm depolama türlerinden kaldırın + +## Hedefler + +**Açık Koleksiyon Oluşturma**: Verilerin depolanabilmesi için koleksiyonların oluşturulmasını gerektirir +**Depolama Senkronizasyonu**: Koleksiyonların tüm depolama arka uçlarında (vektörler, nesneler, üçlüler) mevcut olduğundan emin olun +**Koleksiyon Görünürlüğü**: Kullanıcıların ortamlarındaki tüm koleksiyonları listelemesini ve incelemesini sağlayın +**Koleksiyon Temizleme**: Artık gerekli olmayan koleksiyonların silinmesine izin verin +**Koleksiyon Organizasyonu**: Daha iyi koleksiyon takibi ve keşfi için etiketleri ve kategorileri destekleyin +**Meta Veri Yönetimi**: İşletimsel açıklık için koleksiyonlarla anlamlı meta verileri ilişkilendirin +**Koleksiyon Keşfi**: Filtreleme ve arama yoluyla belirli koleksiyonları bulmayı kolaylaştırın +**İşletim Şeffaflığı**: Koleksiyon yaşam döngüsü ve kullanımı hakkında net görünürlük sağlayın +**Kaynak Yönetimi**: Kullanılmayan koleksiyonları temizleyerek kaynak kullanımını optimize etmeyi sağlayın +**Veri Bütünlüğü**: Meta veri takibi olmadan depolamada yetim koleksiyonların oluşmasını önleyin + +## Arka Plan + +Geçmişte, TrustGraph'taki koleksiyonlar, veri yükleme işlemleri sırasında örtülü olarak oluşturuluyordu ve bu da koleksiyonların depolama arka uçlarında, ancak kütüphanecide ilgili meta verilere sahip olmadan var olabileceği senkronizasyon sorunlarına yol açıyordu. Bu durum, yönetim zorlukları ve potansiyel olarak yetim veri sorunları yaratmıştır. + +Açık koleksiyon oluşturma modeli, bu sorunları aşağıdaki şekilde ele alır: +Koleksiyonların `tg-set-collection` aracılığıyla kullanmadan önce oluşturulmasını gerektirir +Koleksiyon oluşturmayı tüm depolama arka uçlarına yayınlar +Kütüphaneci meta verileri ile depolama arasındaki senkronize durumu korur +Var olmayan koleksiyonlara yazmayı engeller +Açık koleksiyon yaşam döngüsü yönetimi sağlar + +Bu özellik, açık koleksiyon yönetimi modelini tanımlar. Açık koleksiyon oluşturmayı gerektirerek, TrustGraph şunları sağlar: +Koleksiyonlar, oluşturulmadan itibaren kütüphaneci meta verilerinde takip edilir +Tüm depolama arka uçları, verileri almadan önce koleksiyonların varlığından haberdardır +Depolamada yetim koleksiyonların oluşması engellenir +Koleksiyon yaşam döngüsü üzerinde açık işletimsel görünürlük ve kontrol sağlanır +Var olmayan koleksiyonlara yapılan işlemlerde tutarlı hata işleme sağlanır + +## Teknik Tasarım + +### Mimari + +Koleksiyon yönetimi sistemi, mevcut TrustGraph altyapısının içinde uygulanacaktır: + +1. **Kütüphaneci Hizmeti Entegrasyonu** + Koleksiyon yönetimi işlemleri, mevcut kütüphaneci hizmetine eklenecektir + Yeni bir hizmet gerektirmez - mevcut kimlik doğrulama ve erişim kalıplarından yararlanır + Koleksiyon listeleme, silme ve meta veri yönetimi işlemlerini işler + + Modül: trustgraph-librarian + +2. **Cassandra Koleksiyon Meta Veri Tablosu** + Mevcut kütüphaneci anahtar alanındaki yeni bir tablo + Kullanıcı kapsamlı erişim ile koleksiyon meta verilerini depolar + Birincil anahtar: Doğru çoklu kiracılık için (user_id, collection_id) + + Modül: trustgraph-librarian + +3. **Koleksiyon Yönetimi CLI** + Koleksiyon işlemleri için komut satırı arayüzü + Listeleme, silme, etiketleme ve etiket yönetimi komutları sağlar + Mevcut CLI çerçevesiyle entegre olur + + Modül: trustgraph-cli + +### Veri Modelleri + +#### Cassandra Koleksiyon Meta Veri Tablosu + +Koleksiyon meta verileri, kütüphaneci anahtar alanındaki yapılandırılmış bir Cassandra tablosunda saklanacaktır: + +```sql +CREATE TABLE collections ( + user text, + collection text, + name text, + description text, + tags set, + created_at timestamp, + updated_at timestamp, + PRIMARY KEY (user, collection) +); +``` + +Tablo yapısı: +**user**: **collection**: Birincil bileşik anahtar, kullanıcı yalıtımını sağlar +**name**: İnsan tarafından okunabilir koleksiyon adı +**description**: Koleksiyonun amacının ayrıntılı açıklaması +**tags**: Kategorizasyon ve filtreleme için etiket kümesi +**created_at**: Koleksiyon oluşturma zaman damgası +**updated_at**: Son değişiklik zaman damgası + +Bu yaklaşım şunları sağlar: +Kullanıcı yalıtımı ile çoklu kiracılı koleksiyon yönetimi +Kullanıcı ve koleksiyon bazında verimli sorgulama +Düzenleme için esnek etiketleme sistemi +İşletimsel bilgiler için yaşam döngüsü takibi + +#### Koleksiyon Yaşam Döngüsü + +Koleksiyonlar, veri işlemlerine başlamadan önce kütüphanede açıkça oluşturulmalıdır: + +1. **Koleksiyon Oluşturma** (İki Yol): + + **Yol A: Kullanıcı Tarafından Başlatılan Oluşturma** `tg-set-collection` aracılığıyla: + Kullanıcı, koleksiyon kimliği, adı, açıklaması ve etiketleri sağlar + Kütüphane, `collections` tablosunda bir meta veri kaydı oluşturur + Kütüphane, tüm depolama arka uçlarına "create-collection" mesajını gönderir + Tüm depolama işlemcileri, koleksiyonu oluşturur ve başarıyı onaylar + Koleksiyon artık veri işlemleri için hazırdır + + **Yol B: Belge Gönderimi Üzerinde Otomatik Oluşturma**: + Kullanıcı, bir koleksiyon kimliği belirten bir belge gönderir + Kütüphane, koleksiyonun meta veri tablosunda mevcut olup olmadığını kontrol eder + Yoksa: Kütüphane, varsayılanlarla (ad=koleksiyon_kimliği, boş açıklama/etiketler) bir meta veri oluşturur + Kütüphane, tüm depolama arka uçlarına "create-collection" mesajını gönderir + Tüm depolama işlemcileri, koleksiyonu oluşturur ve başarıyı onaylar + Belge işleme, koleksiyonun artık oluşturulduğu şekilde devam eder + + Her iki yol da, veri işlemlerine izin verilmeden önce koleksiyonun kütüphane meta verilerinde VE tüm depolama arka uçlarında mevcut olmasını sağlar. + +2. **Depolama Doğrulama**: Yazma işlemleri, koleksiyonun mevcut olup olmadığını doğrular: + Depolama işlemcileri, yazmayı kabul etmeden önce koleksiyonun durumunu kontrol eder + Mevcut olmayan koleksiyonlara yapılan yazılar hata döndürür + Bu, doğrudan yazmaların kütüphanenin koleksiyon oluşturma mantığını atlamasını engeller + +3. **Sorgu Davranışı**: Sorgu işlemleri, mevcut olmayan koleksiyonları zarif bir şekilde işler: + Mevcut olmayan koleksiyonlara yapılan sorgular boş sonuçlar döndürür + Sorgu işlemleri için hata oluşmaz + Koleksiyonun mevcut olması gerekmeksizin keşfetmeye olanak tanır + +4. **Meta Veri Güncellemeleri**: Kullanıcılar, koleksiyon oluşturulduktan sonra koleksiyon meta verilerini güncelleyebilir: + Adı, açıklamasını ve etiketleri `tg-set-collection` aracılığıyla güncelleyin + Güncellemeler yalnızca kütüphane meta verilerine uygulanır + Depolama arka uçları koleksiyonu korur, ancak meta veri güncellemeleri yayılmaz + +5. **Açık Silme**: Kullanıcılar, koleksiyonları `tg-delete-collection` aracılığıyla siler: + Kütüphane, tüm depolama arka uçlarına "delete-collection" mesajını gönderir + Tüm depolama işlemcilerinden onay bekler + Depolama temizliği tamamlandıktan SONRA yalnızca kütüphane meta veri kaydını siler + Depoda hiçbir verinin kaybolmamasını sağlar + +**Temel İlke**: Kütüphane, koleksiyon oluşturma için tek kontrol noktasıdır. Kullanıcı komutu veya belge gönderimi ile başlatılıp başlatılmadığına bakılmaksızın, kütüphane, veri işlemlerine izin vermeden önce uygun meta veri takibi ve depolama arka uç senkronizasyonunu sağlar. + +Gerekli işlemler: +**Koleksiyon Oluşturma**: `tg-set-collection` aracılığıyla kullanıcı işlemi VEYA belge gönderimi üzerine otomatik +**Koleksiyon Meta Verilerini Güncelleme**: Adı, açıklaması ve etiketleri değiştirmek için kullanıcı işlemi +**Koleksiyonu Silme**: Koleksiyonu ve tüm depolarda verilerini kaldırmak için kullanıcı işlemi +**Koleksiyonları Listeleme**: Etiketlere göre filtreleme ile koleksiyonları görüntülemek için kullanıcı işlemi + +#### Çoklu Depo Koleksiyon Yönetimi + +Koleksiyonlar, TrustGraph'ta birden çok depolama arka uçunda bulunur: +**Vektör Depoları** (Qdrant, Milvus, Pinecone): Gömme ve vektör verilerini depolar +**Nesne Depoları** (Cassandra): Belge ve dosya verilerini depolar +**Üçlü Depolar** (Cassandra, Neo4j, Memgraph, FalkorDB): Grafik/RDF verilerini depolar + +Her bir mağaza türü aşağıdaki işlemleri uygular: +**Koleksiyon Durumu Takibi**: Hangi koleksiyonların mevcut olduğunu takip etme +**Koleksiyon Oluşturma**: "koleksiyon oluştur" işlemlerini kabul etme ve işleme alma +**Koleksiyon Doğrulama**: Yazma işlemlerini kabul etmeden önce koleksiyonun varlığını kontrol etme +**Koleksiyon Silme**: Belirtilen koleksiyon için tüm verileri silme + +Kütüphaneci hizmeti, tüm mağaza türleri arasında koleksiyon işlemlerini koordine ederek şunları sağlar: +Koleksiyonlar, kullanmadan önce tüm arka uçlarda oluşturulur +Tüm arka uçlar, oluşturma işleminden sonra başarıyı doğrular +Depolama türleri arasında senkronize koleksiyon yaşam döngüsü +Koleksiyonlar mevcut olmadığında tutarlı hata işleme + +#### Depolama Türüne Göre Koleksiyon Durumu Takibi + +Her depolama arka ucu, yeteneklerine bağlı olarak koleksiyon durumunu farklı şekilde takip eder: + +**Cassandra Üçlü Deposu:** +Mevcut `triples_collection` tablosunu kullanır +Koleksiyon oluşturulduğunda sistem işaretleyici üçlüsü oluşturur +Sorgu: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1` +Koleksiyonun varlığı için verimli tek bölüm kontrolü + +**Qdrant/Milvus/Pinecone Vektör Depoları:** +Yerel koleksiyon API'leri, varlık kontrolü sağlar +Koleksiyonlar, uygun vektör yapılandırmasıyla oluşturulur +`collection_exists()` yöntemi, depolama API'sini kullanır +Koleksiyon oluşturma, boyut gereksinimlerini doğrular + +**Neo4j/Memgraph/FalkorDB Grafik Depoları:** +Koleksiyonları takip etmek için `:CollectionMetadata` düğümlerini kullanır +Düğüm özellikleri: `{user, collection, created_at}` +Sorgu: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})` +Veri düğümlerinden ayrı olarak, temiz bir ayrım sağlar +Koleksiyon listeleme ve doğrulama için verimli bir yol sağlar + +**Cassandra Nesne Deposu:** +Koleksiyon meta veri tablosunu veya işaretçi satırlarını kullanır +Üçlü depoya benzer bir desen +Veri yazmadan önce koleksiyonu doğrular + +### API'ler + +Koleksiyon Yönetimi API'leri (Kütüphaneci): +**Koleksiyon Oluşturma/Güncelleme**: Yeni bir koleksiyon oluşturma veya mevcut meta verileri `tg-set-collection` aracılığıyla güncelleme +**Koleksiyonları Listeleme**: İsteğe bağlı etiket filtrelemesiyle bir kullanıcı için koleksiyonları alma +**Koleksiyon Silme**: Koleksiyonu ve ilişkili verileri silme, tüm mağaza türlerine kadar yayılma + +Depolama Yönetimi API'leri (Tüm Depolama İşlemcileri): +**Koleksiyon Oluşturma**: "koleksiyon oluştur" işlemini işleme, depolamada koleksiyonu oluşturma +**Koleksiyon Silme**: "koleksiyon sil" işlemini işleme, tüm koleksiyon verilerini silme +**Koleksiyon Varlığı Kontrolü**: Yazma işlemlerini kabul etmeden önce iç doğrulama + +Veri İşlemleri API'leri (Değiştirilmiş Davranış): +**Yazma API'leri**: Veriyi kabul etmeden önce koleksiyonun varlığını doğrulama, mevcut değilse hata döndürme +**Sorgu API'leri**: Hata olmadan mevcut olmayan koleksiyonlar için boş sonuçlar döndürme + +### Uygulama Ayrıntıları + +Uygulama, hizmet entegrasyonu ve CLI komut yapısı için mevcut TrustGraph desenlerini takip edecektir. + +#### Koleksiyon Silme Yayılımı + +Bir kullanıcı, kütüphaneci hizmeti aracılığıyla koleksiyon silme işlemini başlattığında: + +1. **Meta Veri Doğrulama**: Koleksiyonun var olduğunu ve kullanıcının silme izni olup olmadığını doğrulayın +2. **Depolama Yayılımı**: Kütüphaneci, tüm depolama yazıcıları arasında silme işlemini koordine eder: + Vektör depolama yazıcısı: Kullanıcı ve koleksiyon için gömülmeleri ve vektör indekslerini kaldırır + Nesne depolama yazıcısı: Kullanıcı ve koleksiyon için belgeleri ve dosyaları kaldırır + Üçlü depolama yazıcısı: Kullanıcı ve koleksiyon için grafik verilerini ve üçlüleri kaldırır +3. **Meta Veri Temizleme**: Cassandra'dan koleksiyon meta veri kaydını kaldırır +4. **Hata İşleme**: Herhangi bir depolama silme işlemi başarısız olursa, geri alma veya yeniden deneme mekanizmaları aracılığıyla tutarlılığı koruyun + +#### Koleksiyon Yönetimi Arayüzü + +**⚠️ ESKİ YAKLAŞIM - YAPILANDIRMA TEMELLİ DESENE DEĞİŞTİRİLDİ** + +Aşağıda açıklanan kuyruk tabanlı mimari, `CollectionConfigHandler` kullanarak bir yapılandırma tabanlı yaklaşımla değiştirilmiştir. Tüm depolama arka uçları artık özel yönetim kuyrukları yerine yapılandırma itme mesajları aracılığıyla koleksiyon güncellemeleri alır. + +~~Tüm depolama yazıcıları, ortak bir şemaya sahip standart bir koleksiyon yönetimi arayüzü uygular:~~ + +~~**Mesaj Şeması (`StorageManagementRequest`):**~~ +```json +{ + "operation": "create-collection" | "delete-collection", + "user": "user123", + "collection": "documents-2024" +} +``` + +~~**Sıra Mimarisi:**~~ +~~**Vektör Depolama Yönetimi Kuyruğu** (`vector-storage-management`): Vektör/gömme depoları~~ +~~**Nesne Depolama Yönetimi Kuyruğu** (`object-storage-management`): Nesne/belge depoları~~ +~~**Üçlü Depolama Yönetimi Kuyruğu** (`triples-storage-management`): Grafik/RDF depoları~~ +~~**Depolama Yanıt Kuyruğu** (`storage-management-response`): Tüm yanıtlar buraya gönderilir~~ + +**Mevcut Uygulama:** + +Tüm depolama arka uçları artık `CollectionConfigHandler` kullanır: +**Yapılandırma İtme Entegrasyonu**: Depolama hizmetleri, yapılandırma itme bildirimleri için kayıt yaptırır +**Otomatik Senkronizasyon**: Koleksiyonlar, yapılandırma değişikliklerine göre oluşturulur/silinir +**Bildirimsel Model**: Koleksiyonlar, yapılandırma hizmetinde tanımlanır, arka uçlar eşleşmesi için senkronize olur +**İstek/Yanıt Yok**: Koordinasyon yükünü ve yanıt takibini ortadan kaldırır +**Koleksiyon Durumu Takibi**: `known_collections` önbelleği aracılığıyla sürdürülür +**İdeolojik İşlemler**: Aynı yapılandırmayı birden çok kez işlemek güvenlidir + +Her depolama arka ucu şunları uygular: +`create_collection(user: str, collection: str, metadata: dict)` - Koleksiyon yapılarını oluşturur +`delete_collection(user: str, collection: str)` - Tüm koleksiyon verilerini kaldırır +`collection_exists(user: str, collection: str) -> bool` - Yazmadan önce doğrular + +#### Cassandra Üçlü Depolama Yeniden Düzenlemesi + +Bu uygulamanın bir parçası olarak, Cassandra üçlü depolama, bir koleksiyon başına tablo modelinden tek bir tablo modeline yeniden düzenlenecektir: + +**Mevcut Mimari:** +Kullanıcı başına bir anahtar alanı, her koleksiyon için ayrı bir tablo +Şema: `(s, p, o)` ile `PRIMARY KEY (s, p, o)` +Tablo adları: Kullanıcı koleksiyonları, ayrı Cassandra tabloları haline gelir + +**Yeni Mimari:** +Kullanıcı başına bir anahtar alanı, tüm koleksiyonlar için tek bir "üçlüler" tablosu +Şema: `(collection, s, p, o)` ile `PRIMARY KEY (collection, s, p, o)` +Koleksiyon izolasyonu, koleksiyon bölümlendirmesi yoluyla sağlanır + +**Gerekli Değişiklikler:** + +1. **TrustGraph Sınıfı Yeniden Düzenlemesi** (`trustgraph/direct/cassandra.py`): + Oluşturucudan `table` parametresini kaldırın, sabit "üçlüler" tablosunu kullanın + Tüm yöntemlere `collection` parametresini ekleyin + Koleksiyonu ilk sütun olarak içeren şemayı güncelleyin + **Dizin Güncellemeleri**: Tüm 8 sorgu desenini desteklemek için yeni dizinler oluşturulacaktır: + `(s)` üzerine dizin, konu tabanlı sorgular için + `(p)` üzerine dizin, öznelik tabanlı sorgular için + `(o)` üzerine dizin, nesne tabanlı sorgular için + Not: Cassandra, çok sütunlu ikincil dizinleri desteklemez, bu nedenle bunlar tek sütunlu dizinlerdir + + **Sorgu Deseni Performansı:** + ✅ `get_all()` - `collection` üzerinde bölüm taraması + ✅ `get_s(s)` - birincil anahtarı verimli kullanır (`collection, s`) + ✅ `get_p(p)` - `idx_p` ile `collection` filtrelemesini kullanır + ✅ `get_o(o)` - `idx_o` ile `collection` filtrelemesini kullanır + ✅ `get_sp(s, p)` - birincil anahtarı verimli kullanır (`collection, s, p`) + ⚠️ `get_po(p, o)` - `ALLOW FILTERING` gerektirir (ya `idx_p` veya `idx_o` artı filtreleme kullanır) + ✅ `get_os(o, s)` - `idx_o` ile ek filtreleme `s` üzerinde kullanır + ✅ `get_spo(s, p, o)` - tüm birincil anahtarı verimli kullanır + + **ALLOW FILTERING Notu:** `get_po` sorgu deseni, uygun bir birleşik dizin olmadan hem öznitelik hem de nesne kısıtlamalarına ihtiyaç duyduğu için `ALLOW FILTERING` gerektirir. Bu kabul edilebilir çünkü bu sorgu deseni, tipik üçlü depolama kullanımında konu tabanlı sorgulara göre daha az yaygındır + +2. **Depolama Yazarı Güncellemeleri** (`trustgraph/storage/triples/cassandra/write.py`): + (kullanıcı, koleksiyon) başına bir bağlantı yerine, kullanıcı başına tek bir TrustGraph bağlantısı sürdürün + Ekleme işlemlerine koleksiyonu iletin + Daha az bağlantıyla daha verimli kaynak kullanımı + +3. **Sorgu Hizmeti Güncellemeleri** (`trustgraph/query/triples/cassandra/service.py`): + Kullanıcı başına tek bir TrustGraph bağlantısı + Tüm sorgu işlemlerine koleksiyonu iletin + Koleksiyon parametresiyle aynı sorgu mantığını koruyun + +**Faydaları:** +**Basitleştirilmiş Koleksiyon Silme:** Tüm 4 tablo üzerinde `collection` bölüm anahtarını kullanarak silme +**Kaynak Verimliliği:** Daha az veritabanı bağlantısı ve tablo nesnesi +**Çoklu Koleksiyon İşlemleri:** Birden çok koleksiyonu kapsayan işlemleri uygulamak daha kolaydır +**Tutarlı Mimari:** Birleşik koleksiyon meta veri yaklaşımıyla uyumludur +**Koleksiyon Doğrulama:** `triples_collection` tablosu aracılığıyla koleksiyonun varlığını kontrol etmek kolaydır + +Koleksiyon işlemleri, mümkün olduğunda atomik olacak ve uygun hata yönetimi ve doğrulama sağlayacaktır. + +## Güvenlik Hususları + +Koleksiyon yönetimi işlemleri, yetkisiz erişimi veya koleksiyonların silinmesini önlemek için uygun yetkilendirme gerektirir. Erişim kontrolü, mevcut TrustGraph güvenlik modelleriyle uyumlu olacaktır. + +## Performans Hususları + +Koleksiyon listeleme işlemleri, çok sayıda koleksiyon içeren ortamlarda sayfalama gerektirebilir. Meta veri sorguları, yaygın filtreleme kalıpları için optimize edilmelidir. + +## Test Stratejisi + +Kapsamlı testler şunları kapsayacaktır: +Koleksiyon oluşturma iş akışı, uçtan uca +Depolama arka uç senkronizasyonu +Var olmayan koleksiyonlar için yazma doğrulaması +Var olmayan koleksiyonların sorgu işlenmesi +Koleksiyon silme işleminin tüm depolama alanlarında yayılması +Hata yönetimi ve kurtarma senaryoları +Her depolama arka ucu için birim testleri +Çapraz depolama işlemleri için entegrasyon testleri + +## Uygulama Durumu + +### ✅ Tamamlanmış Bileşenler + +1. **Librarian Koleksiyon Yönetimi Hizmeti** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`) + Koleksiyon meta veri CRUD işlemleri (listeleme, güncelleme, silme) + `LibraryTableStore` aracılığıyla Cassandra koleksiyon meta veri tablosu entegrasyonu + Koleksiyon silme işleminin tüm depolama türleri arasında koordinasyonu + Uygun hata yönetimi ile asenkron istek/yanıt işleme + +2. **Koleksiyon Meta Veri Şeması** (`trustgraph-base/trustgraph/schema/services/collection.py`) + `CollectionManagementRequest` ve `CollectionManagementResponse` şemaları + Koleksiyon kayıtları için `CollectionMetadata` şeması + Koleksiyon istek/yanıt kuyruğu konu tanımları + +3. **Depolama Yönetimi Şeması** (`trustgraph-base/trustgraph/schema/services/storage.py`) + `StorageManagementRequest` ve `StorageManagementResponse` şemaları + Depolama yönetimi kuyruğu konuları tanımlandı + Depolama seviyesindeki koleksiyon işlemleri için mesaj formatı + +4. **Cassandra 4-Tablo Şeması** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`) + Sorgu performansı için birleşik bölüm anahtarları + SPO sorguları ve silme takibi için `triples_collection` tablosu + Koleksiyon silme işlemi, okuyup sonra silme kalıbıyla uygulandı + +### ✅ Yapılandırma Tabanlı Kalıba Geçiş - TAMAMLANDI + +**Tüm depolama arka uçları, kuyruk tabanlı kalıptan yapılandırma tabanlı `CollectionConfigHandler` kalıbına geçirildi.** + +Tamamlanan geçişler: +✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` + +Tüm arka uçlar artık: +`CollectionConfigHandler`'dan miras almaktadır +`self.register_config_handler(self.on_collection_config)` aracılığıyla yapılandırma itme bildirimleri için kayıtlıdır +`create_collection(user, collection, metadata)` ve `delete_collection(user, collection)`'i uygulamaktadır +Yazmadan önce `collection_exists(user, collection)` ile doğrulamaktadır +Otomatik olarak yapılandırma hizmeti değişiklikleriyle senkronize olmaktadır + +Eski kuyruk tabanlı altyapı kaldırıldı: +✅ `StorageManagementRequest` ve `StorageManagementResponse` şemaları kaldırıldı +✅ Depolama yönetimi kuyruğu konu tanımları kaldırıldı +✅ Tüm arka uçlardan depolama yönetimi tüketici/üretici kaldırıldı +✅ Tüm arka uçlardan `on_storage_management` işleyicileri kaldırıldı + diff --git a/docs/tech-specs/collection-management.zh-cn.md b/docs/tech-specs/collection-management.zh-cn.md new file mode 100644 index 00000000..dd116f78 --- /dev/null +++ b/docs/tech-specs/collection-management.zh-cn.md @@ -0,0 +1,403 @@ +# Collection Management Technical Specification + +## Overview + +本规范描述了 TrustGraph 的集合管理功能,要求显式创建集合,并提供对集合生命周期的直接控制。在开始使用之前,必须显式创建集合,以确保 librarian 元数据与所有存储后端之间的正确同步。该功能支持四个主要用例: + +1. **集合创建 (Collection Creation)**: 在存储数据之前,显式创建集合。 +2. **集合列表 (Collection Listing)**: 查看系统中所有现有的集合。 +3. **集合元数据管理 (Collection Metadata Management)**: 更新集合的名称、描述和标签。 +4. **集合删除 (Collection Deletion)**: 删除集合及其关联的数据,包括所有存储类型。 + +## Goals + +**显式集合创建 (Explicit Collection Creation)**: 要求在存储数据之前创建集合。 +**存储同步 (Storage Synchronization)**: 确保集合存在于所有存储后端(向量、对象、三元组)中。 +**集合可见性 (Collection Visibility)**: 允许用户列出并检查其环境中的所有集合。 +**集合清理 (Collection Cleanup)**: 允许删除不再需要的集合。 +**集合组织 (Collection Organization)**: 支持标签和标记,以便更好地跟踪和发现集合。 +**元数据管理 (Metadata Management)**: 为集合关联有意义的元数据,以提高操作的清晰度。 +**集合发现 (Collection Discovery)**: 通过过滤和搜索,更容易找到特定的集合。 +**操作透明性 (Operational Transparency)**: 提供对集合生命周期和使用的清晰可见性。 +**资源管理 (Resource Management)**: 允许清理未使用的集合,以优化资源利用率。 +**数据完整性 (Data Integrity)**: 阻止在存储中出现没有元数据跟踪的孤立集合。 + +## Background + +以前,TrustGraph 中的集合是在数据加载操作期间隐式创建的,这会导致同步问题,即集合可能存在于存储后端中,但 librarian 中没有相应的元数据。这带来了管理挑战和潜在的数据孤立问题。 + +显式集合创建模型通过以下方式解决了这些问题: +通过 `tg-set-collection` 要求在开始使用之前创建集合。 +将集合创建广播到所有存储后端。 +维护 librarian 元数据和存储之间的同步状态。 +阻止写入不存在的集合。 +提供清晰的集合生命周期管理。 + +本规范定义了显式集合管理模型。通过要求显式创建集合,TrustGraph 确保: +集合从创建开始就在 librarian 元数据中进行跟踪。 +在接收数据之前,所有存储后端都了解集合。 +存储中不存在孤立的集合。 +对集合生命周期具有清晰的操作可见性和控制。 +当操作引用不存在的集合时,提供一致的错误处理。 + +## Technical Design + +### Architecture + +集合管理系统将实现于现有的 TrustGraph 基础设施中: + +1. **Librarian Service Integration** + 集合管理操作将被添加到现有的 librarian 服务中。 + 不需要新的服务 - 利用现有的身份验证和访问模式。 + 处理集合列表、删除和元数据管理。 + + 模块: trustgraph-librarian + +2. **Cassandra Collection Metadata Table** + 在现有的 librarian keyspace 中创建一个新的表。 + 存储具有用户范围访问权限的集合元数据。 + 主键:(user_id, collection_id),用于适当的多租户支持。 + + 模块: trustgraph-librarian + +3. **Collection Management CLI** + 用于集合操作的命令行界面。 + 提供列表、删除、标签和标记管理命令。 + 与现有的 CLI 框架集成。 + + 模块: trustgraph-cli + +### Data Models + +#### Cassandra Collection Metadata Table + +集合元数据将存储在 librarian keyspace 中的结构化 Cassandra 表中: + +```sql +CREATE TABLE collections ( + user text, + collection text, + name text, + description text, + tags set, + created_at timestamp, + updated_at timestamp, + PRIMARY KEY (user, collection) +); +``` + +表结构: +**user** + **collection**: 复合主键,确保用户隔离 +**name**: 人类可读的集合名称 +**description**: 集合用途的详细描述 +**tags**: 用于分类和过滤的标签集合 +**created_at**: 集合创建时间戳 +**updated_at**: 最后修改时间戳 + +此方法允许: +多租户集合管理,具有用户隔离 +通过用户和集合进行高效查询 +灵活的标签系统,用于组织 +生命周期跟踪,用于运营洞察 + +#### 集合生命周期 + +在进行任何数据操作之前,必须在 librarian 中显式创建集合: + +1. **集合创建** (两种路径): + + **路径 A: 用户发起创建** 通过 `tg-set-collection`: + 用户提供集合 ID、名称、描述和标签 + Librarian 在 `collections` 表中创建元数据记录 + Librarian 向所有存储后端广播 "create-collection" + 所有存储处理器创建集合并确认成功 + 集合现在可以用于数据操作 + + **路径 B: 在文档提交时自动创建**: + 用户提交指定集合 ID 的文档 + Librarian 检查集合是否存在于元数据表中 + 如果不存在: Librarian 使用默认值创建元数据 (name=collection_id, 描述/标签为空) + Librarian 向所有存储后端广播 "create-collection" + 所有存储处理器创建集合并确认成功 + 文档处理继续,此时集合已建立 + + 两种路径都确保集合存在于 librarian 元数据中,并且所有存储后端都已同步,然后再允许进行数据操作。 + +2. **存储验证**: 写入操作验证集合是否存在: + 存储处理器在接受写入操作之前检查集合状态 + 写入不存在的集合会返回错误 + 这可以防止直接写入绕过 librarian 的集合创建逻辑 + +3. **查询行为**: 查询操作可以优雅地处理不存在的集合: + 查询不存在的集合会返回空结果 + 不会为查询操作抛出错误 + 允许探索,而无需集合存在 + +4. **元数据更新**: 用户可以在创建后更新集合元数据: + 通过 `tg-set-collection` 更新名称、描述和标签 + 更新仅应用于 librarian 元数据 + 存储后端保留集合,但元数据更新不会传播 + +5. **显式删除**: 用户通过 `tg-delete-collection` 删除集合: + Librarian 向所有存储后端广播 "delete-collection" + 等待来自所有存储处理器的确认 + 仅在存储清理完成后删除 librarian 元数据记录 + 确保存储中没有孤立数据 + +**关键原则**: librarian 是集合创建的唯一控制点。 无论是通过用户命令还是文档提交发起,librarian 都会确保在允许进行数据操作之前,正确跟踪元数据并与存储后端同步。 + +需要的操作: +**创建集合**: 通过 `tg-set-collection` 进行用户操作,或在文档提交时自动进行 +**更新集合元数据**: 用户操作,用于修改名称、描述和标签 +**删除集合**: 用户操作,用于删除集合及其数据,删除所有存储中的数据 +**列出集合**: 用户操作,用于查看带有标签过滤的集合 + +#### 多存储集合管理 + +集合存在于 TrustGraph 中的多个存储后端中: +**向量存储** (Qdrant, Milvus, Pinecone): 存储嵌入和向量数据 +**对象存储** (Cassandra): 存储文档和文件数据 +**三元存储** (Cassandra, Neo4j, Memgraph, FalkorDB): 存储图/RDF 数据 + +Each store type implements: +**Collection State Tracking**: Maintain knowledge of which collections exist +**Collection Creation**: Accept and process "create-collection" operations +**Collection Validation**: Check collection exists before accepting writes +**Collection Deletion**: Remove all data for specified collection + +The librarian service coordinates collection operations across all store types, ensuring: +Collections created in all backends before use +All backends confirm creation before returning success +Synchronized collection lifecycle across storage types +Consistent error handling when collections don't exist + +#### Collection State Tracking by Storage Type + +Each storage backend tracks collection state differently based on its capabilities: + +**Cassandra Triple Store:** +Uses existing `triples_collection` table +Creates system marker triple when collection created +Query: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1` +Efficient single-partition check for collection existence + +**Qdrant/Milvus/Pinecone Vector Stores:** +Native collection APIs provide existence checking +Collections created with proper vector configuration +`collection_exists()` method uses storage API +Collection creation validates dimension requirements + +**Neo4j/Memgraph/FalkorDB Graph Stores:** +Use `:CollectionMetadata` nodes to track collections +Node properties: `{user, collection, created_at}` +Query: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})` +Separate from data nodes for clean separation +Enables efficient collection listing and validation + +**Cassandra Object Store:** +Uses collection metadata table or marker rows +Similar pattern to triple store +Validates collection before document writes + +### APIs + +Collection Management APIs (Librarian): +**Create/Update Collection**: Create new collection or update existing metadata via `tg-set-collection` +**List Collections**: Retrieve collections for a user with optional tag filtering +**Delete Collection**: Remove collection and associated data, cascading to all store types + +Storage Management APIs (All Storage Processors): +**Create Collection**: Handle "create-collection" operation, establish collection in storage +**Delete Collection**: Handle "delete-collection" operation, remove all collection data +**Collection Exists Check**: Internal validation before accepting write operations + +Data Operation APIs (Modified Behavior): +**Write APIs**: Validate collection exists before accepting data, return error if not +**Query APIs**: Return empty results for non-existent collections without error + +### Implementation Details + +The implementation will follow existing TrustGraph patterns for service integration and CLI command structure. + +#### Collection Deletion Cascade + +When a user initiates collection deletion through the librarian service: + +1. **Metadata Validation**: Verify collection exists and user has permission to delete +2. **Store Cascade**: Librarian coordinates deletion across all store writers: + Vector store writer: Remove embeddings and vector indexes for the user and collection + Object store writer: Remove documents and files for the user and collection + Triple store writer: Remove graph data and triples for the user and collection +3. **Metadata Cleanup**: Remove collection metadata record from Cassandra +4. **Error Handling**: If any store deletion fails, maintain consistency through rollback or retry mechanisms + +#### Collection Management Interface + +**⚠️ LEGACY APPROACH - REPLACED BY CONFIG-BASED PATTERN** + +The queue-based architecture described below has been replaced with a config-based approach using `CollectionConfigHandler`. All storage backends now receive collection updates via config push messages instead of dedicated management queues. + +~~All store writers implement a standardized collection management interface with a common schema:~~ + +~~**Message Schema (`StorageManagementRequest`):**~~ +```json +{ + "operation": "create-collection" | "delete-collection", + "user": "user123", + "collection": "documents-2024" +} +``` + +~~**队列架构:**~~ +~~**向量存储管理队列** (`vector-storage-management`): 向量/嵌入式存储~~ +~~**对象存储管理队列** (`object-storage-management`): 对象/文档存储~~ +~~**三元组存储管理队列** (`triples-storage-management`): 图/RDF 存储~~ +~~**存储响应队列** (`storage-management-response`): 所有响应都发送到此处~~ + +**当前实现:** + +所有存储后端现在都使用 `CollectionConfigHandler`: +**配置推送集成**: 存储服务注册以接收配置推送通知 +**自动同步**: 基于配置更改创建/删除集合 +**声明式模型**: 集合在配置服务中定义,后端同步以匹配 +**无请求/响应**: 消除协调开销和响应跟踪 +**集合状态跟踪**: 通过 `known_collections` 缓存维护 +**幂等操作**: 安全地多次处理相同的配置 + +每个存储后端实现: +`create_collection(user: str, collection: str, metadata: dict)` - 创建集合结构 +`delete_collection(user: str, collection: str)` - 移除所有集合数据 +`collection_exists(user: str, collection: str) -> bool` - 在写入之前进行验证 + +#### Cassandra 三元组存储重构 + +作为此实现的组成部分,Cassandra 三元组存储将从每个集合一个表的模型重构为统一的表模型: + +**当前架构:** +每个用户的键空间,每个集合的单独表 +模式:`(s, p, o)` with `PRIMARY KEY (s, p, o)` +表名:用户集合成为单独的 Cassandra 表 + +**新的架构:** +每个用户的键空间,用于所有集合的单个 "triples" 表 +模式:`(collection, s, p, o)` with `PRIMARY KEY (collection, s, p, o)` +通过集合分区实现集合隔离 + +**需要更改的内容:** + +1. **TrustGraph 类重构** (`trustgraph/direct/cassandra.py`): + 移除构造函数中的 `table` 参数,使用固定的 "triples" 表 + 在所有方法中添加 `collection` 参数 + 更新模式以包含集合作为第一列 + **索引更新**: 将创建新的索引以支持所有 8 个查询模式: + 在 `(s)` 上创建索引以进行基于主体的查询 + 在 `(p)` 上创建索引以进行基于谓词的查询 + 在 `(o)` 上创建索引以进行基于对象的查询 + 注意:Cassandra 不支持多列二级索引,因此这些是单列索引 + + **查询模式性能:** + ✅ `get_all()` - 在 `collection` 上进行分区扫描 + ✅ `get_s(s)` - 效率地使用主键 (`collection, s`) + ✅ `get_p(p)` - 使用 `idx_p` 并进行 `collection` 过滤 + ✅ `get_o(o)` - 使用 `idx_o` 并进行 `collection` 过滤 + ✅ `get_sp(s, p)` - 效率地使用主键 (`collection, s, p`) + ⚠️ `get_po(p, o)` - 需要 `ALLOW FILTERING` (使用 `idx_p` 或 `idx_o` 加上过滤) + ✅ `get_os(o, s)` - 使用 `idx_o` 并进行额外的 `s` 过滤 + ✅ `get_spo(s, p, o)` - 效率地使用完整主键 + + **关于 ALLOW FILTERING 的说明**: `get_po` 查询模式需要 `ALLOW FILTERING`,因为它需要谓词和对象约束,而没有合适的复合索引。 这是一个可以接受的,因为此查询模式比在典型的三元组存储用例中基于主体的查询不太常见。 + +2. **存储写入器更新** (`trustgraph/storage/triples/cassandra/write.py`): + 维护每个用户单个 TrustGraph 连接,而不是每个 (用户, 集合) + 将集合传递给插入操作 + 通过减少连接数提高资源利用率 + +3. **查询服务更新** (`trustgraph/query/triples/cassandra/service.py`): + 每个用户的单个 TrustGraph 连接 + 将集合传递给所有查询操作 + 保持相同的查询逻辑,并带有集合参数 + +**优点:** +**简化集合删除**: 使用 `collection` 分区键删除所有 4 个表 +**资源效率**: 减少数据库连接和表对象 +**跨集合操作**: 更容易实现跨多个集合的操作 +**一致的架构**: 与统一的集合元数据方法保持一致 +**集合验证**: 可以通过 `triples_collection` 表轻松检查集合是否存在 + +集合操作在可能的情况下将是原子操作,并提供适当的错误处理和验证。 + +## 安全性考虑 + +集合管理操作需要适当的授权,以防止未经授权的访问或删除集合。 访问控制将与现有的 TrustGraph 安全模型保持一致。 + +## 性能考虑 + +集合列表操作可能需要分页,以适应具有大量集合的环境。 元数据查询应针对常见的过滤模式进行优化。 + +## 测试策略 + +综合测试将涵盖: +集合创建工作流程的端到端流程 +存储后端同步 +对不存在集合的写入验证 +对不存在集合的查询处理 +集合删除在所有存储中的级联操作 +错误处理和恢复场景 +每个存储后端的单元测试 +跨存储操作的集成测试 + +## 实施状态 + +### ✅ 已完成的组件 + +1. **Librarian 集合管理服务** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`) + 集合元数据 CRUD 操作(列表、更新、删除) + 通过 `LibraryTableStore` 与 Cassandra 集合元数据表集成 + 集合删除在所有存储类型上的级联协调 + 具有适当错误管理的异步请求/响应处理 + +2. **集合元数据模式** (`trustgraph-base/trustgraph/schema/services/collection.py`) + `CollectionManagementRequest` 和 `CollectionManagementResponse` 模式 + `CollectionMetadata` 模式用于集合记录 + 集合请求/响应队列主题定义 + +3. **存储管理模式** (`trustgraph-base/trustgraph/schema/services/storage.py`) + `StorageManagementRequest` 和 `StorageManagementResponse` 模式 + 定义了存储管理队列主题 + 存储级别集合操作的消息格式 + +4. **Cassandra 4-表模式** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`) + 用于查询性能的复合分区键 + `triples_collection` 表用于 SPO 查询和删除跟踪 + 集合删除使用读后删除模式实现 + +### ✅ 迁移到基于配置的模式 - 已完成 + +**所有存储后端已从基于队列的模式迁移到基于配置的 `CollectionConfigHandler` 模式。** + +已完成的迁移: +✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` + +所有后端现在: +继承自 `CollectionConfigHandler` +通过 `self.register_config_handler(self.on_collection_config)` 注册配置推送通知 +实施 `create_collection(user, collection, metadata)` 和 `delete_collection(user, collection)` +使用 `collection_exists(user, collection)` 在写入之前进行验证 +自动与配置服务更改同步 + +移除了旧的基于队列的基础设施: +✅ 移除了 `StorageManagementRequest` 和 `StorageManagementResponse` 模式 +✅ 移除了存储管理队列主题定义 +✅ 移除了所有后端中的存储管理生产者/消费者 +✅ 移除了所有后端中的 `on_storage_management` 处理程序 + diff --git a/docs/tech-specs/document-embeddings-chunk-id.ar.md b/docs/tech-specs/document-embeddings-chunk-id.ar.md new file mode 100644 index 00000000..de61c638 --- /dev/null +++ b/docs/tech-specs/document-embeddings-chunk-id.ar.md @@ -0,0 +1,136 @@ +# تضمينات المستندات - مُعرّف الجزء + +## نظرة عامة + +تخزين تضمينات المستندات يخزن حاليًا نص الجزء مباشرةً في حمولة مخزن المتجهات، مما يكرر البيانات الموجودة في Garage. يحل هذا المخطط تخزين نص الجزء باستخدام مراجع `chunk_id`. + +## الحالة الحالية + +```python +@dataclass +class ChunkEmbeddings: + chunk: bytes = b"" + vectors: list[list[float]] = field(default_factory=list) + +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunks: list[str] = field(default_factory=list) +``` + +حمولة تخزين المتجهات: +```python +payload={"doc": chunk} # Duplicates Garage content +``` + +## التصميم + +### تغييرات المخطط + +**ChunkEmbeddings** - استبدال "chunk" بـ "chunk_id": +```python +@dataclass +class ChunkEmbeddings: + chunk_id: str = "" + vectors: list[list[float]] = field(default_factory=list) +``` + +**DocumentEmbeddingsResponse** - إرجاع معرفات الأجزاء (chunk_ids) بدلاً من الأجزاء نفسها: +```python +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunk_ids: list[str] = field(default_factory=list) +``` + +### حمولة مستودع المتجهات + +جميع المستودعات (Qdrant، Milvus، Pinecone): +```python +payload={"chunk_id": chunk_id} +``` + +### التغييرات في معالج مستند RAG + +يقوم معالج مستند RAG باسترداد محتوى الأجزاء من نظام Garage: + +```python +# Get chunk_ids from embeddings store +chunk_ids = await self.rag.doc_embeddings_client.query(...) + +# Fetch chunk content from Garage +docs = [] +for chunk_id in chunk_ids: + content = await self.rag.librarian_client.get_document_content( + chunk_id, self.user + ) + docs.append(content) +``` + +### التغييرات في واجهة برمجة التطبيقات (API) / مجموعة تطوير البرمجيات (SDK) + +**DocumentEmbeddingsClient** تُرجع `chunk_ids`: +```python +return resp.chunk_ids # Changed from resp.chunks +``` + +**تنسيق البيانات** (DocumentEmbeddingsResponseTranslator): +```python +result["chunk_ids"] = obj.chunk_ids # Changed from chunks +``` + +### تغييرات واجهة سطر الأوامر (CLI) + +تعرض أداة واجهة سطر الأوامر (CLI) معرفات الأجزاء (يمكن للمستخدمين استرداد المحتوى بشكل منفصل إذا لزم الأمر). + +## الملفات التي يجب تعديلها + +### المخطط (Schema) +`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - ChunkEmbeddings +`trustgraph-base/trustgraph/schema/services/query.py` - DocumentEmbeddingsResponse + +### الرسائل/المترجمات +`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - DocumentEmbeddingsResponseTranslator + +### العميل (Client) +`trustgraph-base/trustgraph/base/document_embeddings_client.py` - إرجاع معرفات الأجزاء + +### حزمة تطوير البرمجيات (SDK) / واجهة برمجة التطبيقات (API) بلغة بايثون +`trustgraph-base/trustgraph/api/flow.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/socket_client.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/async_flow.py` - إذا كان ذلك ممكنًا +`trustgraph-base/trustgraph/api/bulk_client.py` - استيراد/تصدير تضمينات المستندات +`trustgraph-base/trustgraph/api/async_bulk_client.py` - استيراد/تصدير تضمينات المستندات + +### خدمة التضمينات +`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - تمرير معرف الجزء + +### أدوات الكتابة في التخزين +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` + +### خدمات الاستعلام +`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py` + +### البوابة (Gateway) +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py` + +### استرجاع المعلومات من المستندات (Document RAG) +`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - إضافة عميل أمين المكتبة +`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - الاسترداد من Garage + +### واجهة سطر الأوامر (CLI) +`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py` +`trustgraph-cli/trustgraph/cli/save_doc_embeds.py` +`trustgraph-cli/trustgraph/cli/load_doc_embeds.py` + +## الفوائد + +1. مصدر واحد للحقيقة - نص الأجزاء فقط في Garage +2. تقليل مساحة التخزين في مخزن المتجهات +3. يتيح تتبع مصدر المعلومات في وقت الاستعلام عبر معرف الجزء. diff --git a/docs/tech-specs/document-embeddings-chunk-id.es.md b/docs/tech-specs/document-embeddings-chunk-id.es.md new file mode 100644 index 00000000..f8f8532f --- /dev/null +++ b/docs/tech-specs/document-embeddings-chunk-id.es.md @@ -0,0 +1,136 @@ +# Identificador de fragmento de incrustaciones de documentos + +## Resumen + +Actualmente, el almacenamiento de incrustaciones de documentos almacena directamente el texto del fragmento en la carga útil de la base de datos vectorial, duplicando datos que existen en Garage. Esta especificación reemplaza el almacenamiento del texto del fragmento con referencias `chunk_id`. + +## Estado actual + +```python +@dataclass +class ChunkEmbeddings: + chunk: bytes = b"" + vectors: list[list[float]] = field(default_factory=list) + +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunks: list[str] = field(default_factory=list) +``` + +Carga útil del almacén de vectores: +```python +payload={"doc": chunk} # Duplicates Garage content +``` + +## Diseño + +### Cambios en el esquema + +**ChunkEmbeddings** - reemplazar "chunk" con "chunk_id": +```python +@dataclass +class ChunkEmbeddings: + chunk_id: str = "" + vectors: list[list[float]] = field(default_factory=list) +``` + +**DocumentEmbeddingsResponse** - devolver `chunk_ids` en lugar de `chunks`: +```python +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunk_ids: list[str] = field(default_factory=list) +``` + +### Carga útil del almacén de vectores + +Todos los almacenes (Qdrant, Milvus, Pinecone): +```python +payload={"chunk_id": chunk_id} +``` + +### Cambios en el Documento RAG + +El procesador de documentos RAG recupera el contenido de los fragmentos de Garage: + +```python +# Get chunk_ids from embeddings store +chunk_ids = await self.rag.doc_embeddings_client.query(...) + +# Fetch chunk content from Garage +docs = [] +for chunk_id in chunk_ids: + content = await self.rag.librarian_client.get_document_content( + chunk_id, self.user + ) + docs.append(content) +``` + +### Cambios en la API/SDK + +**DocumentEmbeddingsClient** devuelve chunk_ids: +```python +return resp.chunk_ids # Changed from resp.chunks +``` + +**Formato de cable** (DocumentEmbeddingsResponseTranslator): +```python +result["chunk_ids"] = obj.chunk_ids # Changed from chunks +``` + +### Cambios en la CLI + +La herramienta de la CLI muestra los chunk_ids (los usuarios pueden obtener el contenido por separado si es necesario). + +## Archivos a Modificar + +### Esquema +`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - ChunkEmbeddings +`trustgraph-base/trustgraph/schema/services/query.py` - DocumentEmbeddingsResponse + +### Mensajería/Traductores +`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - DocumentEmbeddingsResponseTranslator + +### Cliente +`trustgraph-base/trustgraph/base/document_embeddings_client.py` - return chunk_ids + +### SDK/API de Python +`trustgraph-base/trustgraph/api/flow.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/socket_client.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/async_flow.py` - if applicable +`trustgraph-base/trustgraph/api/bulk_client.py` - import/export document embeddings +`trustgraph-base/trustgraph/api/async_bulk_client.py` - import/export document embeddings + +### Servicio de Embeddings +`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - pass chunk_id + +### Escritores de Almacenamiento +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` + +### Servicios de Consulta +`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py` + +### Gateway +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py` + +### Document RAG +`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - add librarian client +`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - fetch from Garage + +### CLI +`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py` +`trustgraph-cli/trustgraph/cli/save_doc_embeds.py` +`trustgraph-cli/trustgraph/cli/load_doc_embeds.py` + +## Beneficios + +1. Única fuente de verdad: solo el texto de los chunks en Garage. +2. Almacenamiento de vectores reducido. +3. Permite el rastreo de origen en tiempo de consulta a través del chunk_id. diff --git a/docs/tech-specs/document-embeddings-chunk-id.he.md b/docs/tech-specs/document-embeddings-chunk-id.he.md new file mode 100644 index 00000000..570cd035 --- /dev/null +++ b/docs/tech-specs/document-embeddings-chunk-id.he.md @@ -0,0 +1,136 @@ +# מזהה מקטע של הטמעות מסמכים + +## סקירה כללית + +אחסון הטמעות מסמכים מאחסן כרגע את הטקסט של המקטעים ישירות בתוך מטען ה-vector store, מה שמשכפל נתונים הקיימים ב-Garage. מפרט זה מחליף את אחסון הטקסט של המקטעים עם הפניות ל-`chunk_id`. + +## מצב נוכחי + +```python +@dataclass +class ChunkEmbeddings: + chunk: bytes = b"" + vectors: list[list[float]] = field(default_factory=list) + +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunks: list[str] = field(default_factory=list) +``` + +מטען אחסון וקטורים: +```python +payload={"doc": chunk} # Duplicates Garage content +``` + +## עיצוב + +### שינויים בסכימה + +**ChunkEmbeddings** - החלפת "chunk" ב-"chunk_id": +```python +@dataclass +class ChunkEmbeddings: + chunk_id: str = "" + vectors: list[list[float]] = field(default_factory=list) +``` + +**תגובת DocumentEmbeddingsResponse** - החזרת מזהי חלקים (chunk_ids) במקום חלקים (chunks): +```python +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunk_ids: list[str] = field(default_factory=list) +``` + +### מטען של אחסון וקטורים + +כל האחסונים (Qdrant, Milvus, Pinecone): +```python +payload={"chunk_id": chunk_id} +``` + +### שינויים במסמך RAG + +מעבד מסמכי ה-RAG שולף תוכן מקטעים מ-Garage: + +```python +# Get chunk_ids from embeddings store +chunk_ids = await self.rag.doc_embeddings_client.query(...) + +# Fetch chunk content from Garage +docs = [] +for chunk_id in chunk_ids: + content = await self.rag.librarian_client.get_document_content( + chunk_id, self.user + ) + docs.append(content) +``` + +### שינויים ב-API/SDK + +**DocumentEmbeddingsClient** מחזיר את chunk_ids: +```python +return resp.chunk_ids # Changed from resp.chunks +``` + +**פורמט של נתונים** (DocumentEmbeddingsResponseTranslator): +```python +result["chunk_ids"] = obj.chunk_ids # Changed from chunks +``` + +### שינויים בממשק שורת הפקודה (CLI) + +כלי ה-CLI מציג מזהי חלקים (chunk_ids) (המשתמשים יכולים לשלוף את התוכן בנפרד אם יש צורך). + +## קבצים לשינוי + +### סכימה (Schema) +`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - ChunkEmbeddings +`trustgraph-base/trustgraph/schema/services/query.py` - DocumentEmbeddingsResponse + +### הודעות/מתרגמים +`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - DocumentEmbeddingsResponseTranslator + +### לקוח (Client) +`trustgraph-base/trustgraph/base/document_embeddings_client.py` - החזרת מזהי חלקים (chunk_ids) + +### ערכת פיתוח תוכנה (SDK) / API בפייתון +`trustgraph-base/trustgraph/api/flow.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/socket_client.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/async_flow.py` - אם רלוונטי +`trustgraph-base/trustgraph/api/bulk_client.py` - ייבוא/ייצוא של הטמעות מסמכים (document embeddings) +`trustgraph-base/trustgraph/api/async_bulk_client.py` - ייבוא/ייצוא של הטמעות מסמכים (document embeddings) + +### שירות הטמעות +`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - העברת מזהה חלק (chunk_id) + +### כותבי אחסון +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` + +### שירותי שאילתות +`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py` + +### שער (Gateway) +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py` + +### אחזור מידע ממסמכים (Document RAG) +`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - הוספת לקוח של "ספרן" (librarian) +`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - שליפה מ-"Garage" + +### ממשק שורת הפקודה (CLI) +`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py` +`trustgraph-cli/trustgraph/cli/save_doc_embeds.py` +`trustgraph-cli/trustgraph/cli/load_doc_embeds.py` + +## יתרונות + +1. מקור יחיד לאמת - טקסט החלקים נמצא רק ב-"Garage". +2. הפחתת נפח האחסון של מאגר הווקטורים. +3. מאפשר מעקב אחר מקור המידע בזמן השאילתה באמצעות מזהה החלק (chunk_id). diff --git a/docs/tech-specs/document-embeddings-chunk-id.hi.md b/docs/tech-specs/document-embeddings-chunk-id.hi.md new file mode 100644 index 00000000..4f53dfd5 --- /dev/null +++ b/docs/tech-specs/document-embeddings-chunk-id.hi.md @@ -0,0 +1,136 @@ +# दस्तावेज़ एम्बेडिंग चंक आईडी + +## अवलोकन + +वर्तमान में, दस्तावेज़ एम्बेडिंग स्टोरेज चंक टेक्स्ट को सीधे वेक्टर स्टोर पेलोड में संग्रहीत करता है, जिससे गैरेज में मौजूद डेटा दोहराया जाता है। यह विनिर्देश चंक टेक्स्ट स्टोरेज को `chunk_id` संदर्भों से बदल देता है। + +## वर्तमान स्थिति + +```python +@dataclass +class ChunkEmbeddings: + chunk: bytes = b"" + vectors: list[list[float]] = field(default_factory=list) + +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunks: list[str] = field(default_factory=list) +``` + +वेक्टर स्टोर पेलोड: +```python +payload={"doc": chunk} # Duplicates Garage content +``` + +## डिज़ाइन + +### स्कीमा में बदलाव + +**ChunkEmbeddings** - "chunk" को "chunk_id" से बदलें: +```python +@dataclass +class ChunkEmbeddings: + chunk_id: str = "" + vectors: list[list[float]] = field(default_factory=list) +``` + +**DocumentEmbeddingsResponse** - चंक्स के बजाय chunk_ids लौटाएं: +```python +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunk_ids: list[str] = field(default_factory=list) +``` + +### वेक्टर स्टोर पेलोड + +सभी स्टोर (क्यूड्रेंट, मिल्वस, पाइनकोन): +```python +payload={"chunk_id": chunk_id} +``` + +### दस्तावेज़ आरएजी (RAG) में बदलाव + +दस्तावेज़ आरएजी प्रोसेसर, गराज (Garage) से चंक सामग्री प्राप्त करता है: + +```python +# Get chunk_ids from embeddings store +chunk_ids = await self.rag.doc_embeddings_client.query(...) + +# Fetch chunk content from Garage +docs = [] +for chunk_id in chunk_ids: + content = await self.rag.librarian_client.get_document_content( + chunk_id, self.user + ) + docs.append(content) +``` + +### एपीआई/एसडीके में बदलाव + +**DocumentEmbeddingsClient** चंक_आईडी (chunk_ids) लौटाता है: +```python +return resp.chunk_ids # Changed from resp.chunks +``` + +**वायर प्रारूप** (DocumentEmbeddingsResponseTranslator): +```python +result["chunk_ids"] = obj.chunk_ids # Changed from chunks +``` + +### CLI में बदलाव + +CLI टूल `chunk_ids` प्रदर्शित करता है (उपयोगकर्ता आवश्यकता पड़ने पर सामग्री को अलग से प्राप्त कर सकते हैं)। + +## संशोधित करने योग्य फाइलें + +### स्कीमा +`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - `ChunkEmbeddings` +`trustgraph-base/trustgraph/schema/services/query.py` - `DocumentEmbeddingsResponse` + +### मैसेजिंग/अनुवादक +`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - `DocumentEmbeddingsResponseTranslator` + +### क्लाइंट +`trustgraph-base/trustgraph/base/document_embeddings_client.py` - `chunk_ids` लौटाएं + +### पायथन SDK/API +`trustgraph-base/trustgraph/api/flow.py` - `document_embeddings_query` +`trustgraph-base/trustgraph/api/socket_client.py` - `document_embeddings_query` +`trustgraph-base/trustgraph/api/async_flow.py` - यदि लागू हो +`trustgraph-base/trustgraph/api/bulk_client.py` - दस्तावेज़ एम्बेडिंग का आयात/निर्यात +`trustgraph-base/trustgraph/api/async_bulk_client.py` - दस्तावेज़ एम्बेडिंग का आयात/निर्यात + +### एम्बेडिंग सेवा +`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - `chunk_id` पास करें + +### स्टोरेज राइटर +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` + +### क्वेरी सेवाएं +`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py` + +### गेटवे +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py` + +### दस्तावेज़ RAG +`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - लाइब्रेरियन क्लाइंट जोड़ें +`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - गैरेज से प्राप्त करें + +### CLI +`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py` +`trustgraph-cli/trustgraph/cli/save_doc_embeds.py` +`trustgraph-cli/trustgraph/cli/load_doc_embeds.py` + +## लाभ + +1. सत्य का एकल स्रोत - केवल गैरेज में टेक्स्ट चंक +2. वेक्टर स्टोर स्टोरेज में कमी +3. `chunk_id` के माध्यम से क्वेरी-टाइम उत्पत्ति को सक्षम करता है diff --git a/docs/tech-specs/document-embeddings-chunk-id.pt.md b/docs/tech-specs/document-embeddings-chunk-id.pt.md new file mode 100644 index 00000000..7ebe6101 --- /dev/null +++ b/docs/tech-specs/document-embeddings-chunk-id.pt.md @@ -0,0 +1,136 @@ +# Incorporações de Documentos - ID do Trecho + +## Visão Geral + +Atualmente, o armazenamento de incorporações de documentos armazena o texto do trecho diretamente no payload do armazenamento vetorial, duplicando dados que já existem no Garage. Esta especificação substitui o armazenamento do texto do trecho por referências `chunk_id`. + +## Estado Atual + +```python +@dataclass +class ChunkEmbeddings: + chunk: bytes = b"" + vectors: list[list[float]] = field(default_factory=list) + +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunks: list[str] = field(default_factory=list) +``` + +Payload do armazenamento vetorial: +```python +payload={"doc": chunk} # Duplicates Garage content +``` + +## Design + +### Schema Changes + +**ChunkEmbeddings** - substituir "chunk" por "chunk_id": +```python +@dataclass +class ChunkEmbeddings: + chunk_id: str = "" + vectors: list[list[float]] = field(default_factory=list) +``` + +**DocumentEmbeddingsResponse** - retornar chunk_ids em vez de chunks: +```python +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunk_ids: list[str] = field(default_factory=list) +``` + +### Carga Útil do Armazenamento Vetorial + +Todos os armazenamentos (Qdrant, Milvus, Pinecone): +```python +payload={"chunk_id": chunk_id} +``` + +### Alterações no Processador de Documentos RAG + +O processador de documentos RAG busca o conteúdo dos fragmentos do Garage: + +```python +# Get chunk_ids from embeddings store +chunk_ids = await self.rag.doc_embeddings_client.query(...) + +# Fetch chunk content from Garage +docs = [] +for chunk_id in chunk_ids: + content = await self.rag.librarian_client.get_document_content( + chunk_id, self.user + ) + docs.append(content) +``` + +### Alterações na API/SDK + +**DocumentEmbeddingsClient** retorna chunk_ids: +```python +return resp.chunk_ids # Changed from resp.chunks +``` + +**Formato de dados** (DocumentEmbeddingsResponseTranslator): +```python +result["chunk_ids"] = obj.chunk_ids # Changed from chunks +``` + +### Alterações na CLI + +A ferramenta CLI exibe os chunk_ids (os chamadores podem buscar o conteúdo separadamente, se necessário). + +## Arquivos a serem modificados + +### Schema +`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - ChunkEmbeddings +`trustgraph-base/trustgraph/schema/services/query.py` - DocumentEmbeddingsResponse + +### Mensagens/Tradutores +`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - DocumentEmbeddingsResponseTranslator + +### Cliente +`trustgraph-base/trustgraph/base/document_embeddings_client.py` - retornar chunk_ids + +### SDK/API Python +`trustgraph-base/trustgraph/api/flow.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/socket_client.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/async_flow.py` - se aplicável +`trustgraph-base/trustgraph/api/bulk_client.py` - importar/exportar embeddings de documentos +`trustgraph-base/trustgraph/api/async_bulk_client.py` - importar/exportar embeddings de documentos + +### Serviço de Embeddings +`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - passar chunk_id + +### Escritores de Armazenamento +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` + +### Serviços de Consulta +`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py` + +### Gateway +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py` + +### Document RAG +`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - adicionar cliente librarian +`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - buscar do Garage + +### CLI +`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py` +`trustgraph-cli/trustgraph/cli/save_doc_embeds.py` +`trustgraph-cli/trustgraph/cli/load_doc_embeds.py` + +## Benefícios + +1. Única fonte de verdade - texto do chunk apenas no Garage +2. Redução do armazenamento do vetor +3. Permite a rastreabilidade em tempo de consulta via chunk_id diff --git a/docs/tech-specs/document-embeddings-chunk-id.ru.md b/docs/tech-specs/document-embeddings-chunk-id.ru.md new file mode 100644 index 00000000..7b09511a --- /dev/null +++ b/docs/tech-specs/document-embeddings-chunk-id.ru.md @@ -0,0 +1,136 @@ +# Идентификатор фрагмента встраиваний документов + +## Обзор + +В настоящее время хранилище встраиваний документов хранит текст фрагментов непосредственно в полезной нагрузке векторного хранилища, дублируя данные, которые существуют в Garage. Данная спецификация заменяет хранение текста фрагментов ссылками на `chunk_id`. + +## Текущее состояние + +```python +@dataclass +class ChunkEmbeddings: + chunk: bytes = b"" + vectors: list[list[float]] = field(default_factory=list) + +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunks: list[str] = field(default_factory=list) +``` + +Структура данных для хранения векторов: +```python +payload={"doc": chunk} # Duplicates Garage content +``` + +## Дизайн + +### Изменения схемы + +**ChunkEmbeddings** - заменить "chunk" на "chunk_id": +```python +@dataclass +class ChunkEmbeddings: + chunk_id: str = "" + vectors: list[list[float]] = field(default_factory=list) +``` + +**DocumentEmbeddingsResponse** - возвращать chunk_ids вместо фрагментов: +```python +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunk_ids: list[str] = field(default_factory=list) +``` + +### Структура данных для векторного хранилища + +Все хранилища (Qdrant, Milvus, Pinecone): +```python +payload={"chunk_id": chunk_id} +``` + +### Изменения в системе извлечения информации (RAG) + +Модуль обработки документов RAG извлекает содержимое фрагментов из системы Garage: + +```python +# Get chunk_ids from embeddings store +chunk_ids = await self.rag.doc_embeddings_client.query(...) + +# Fetch chunk content from Garage +docs = [] +for chunk_id in chunk_ids: + content = await self.rag.librarian_client.get_document_content( + chunk_id, self.user + ) + docs.append(content) +``` + +### Изменения API/SDK + +**DocumentEmbeddingsClient** возвращает chunk_ids: +```python +return resp.chunk_ids # Changed from resp.chunks +``` + +**Формат данных** (DocumentEmbeddingsResponseTranslator): +```python +result["chunk_ids"] = obj.chunk_ids # Changed from chunks +``` + +### Изменения в CLI + +Инструмент CLI отображает идентификаторы фрагментов (пользователи могут извлекать контент отдельно, если это необходимо). + +## Файлы для изменения + +### Схема +`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - ChunkEmbeddings +`trustgraph-base/trustgraph/schema/services/query.py` - DocumentEmbeddingsResponse + +### Сообщения/Переводчики +`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - DocumentEmbeddingsResponseTranslator + +### Клиент +`trustgraph-base/trustgraph/base/document_embeddings_client.py` - возвращать идентификаторы фрагментов + +### Python SDK/API +`trustgraph-base/trustgraph/api/flow.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/socket_client.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/async_flow.py` - если применимо +`trustgraph-base/trustgraph/api/bulk_client.py` - импорт/экспорт векторных представлений документов +`trustgraph-base/trustgraph/api/async_bulk_client.py` - импорт/экспорт векторных представлений документов + +### Сервис векторных представлений +`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - передавать идентификатор фрагмента + +### Модули записи в хранилище +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` + +### Сервисы запросов +`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py` + +### Шлюз +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py` + +### Document RAG +`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - добавить клиент librarian +`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - извлекать из Garage + +### CLI +`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py` +`trustgraph-cli/trustgraph/cli/save_doc_embeds.py` +`trustgraph-cli/trustgraph/cli/load_doc_embeds.py` + +## Преимущества + +1. Единый источник истины - текст фрагментов только в Garage +2. Уменьшение объема хранимых векторных представлений +3. Обеспечивает отслеживание происхождения данных в момент запроса с помощью идентификатора фрагмента. diff --git a/docs/tech-specs/document-embeddings-chunk-id.sw.md b/docs/tech-specs/document-embeddings-chunk-id.sw.md new file mode 100644 index 00000000..470cebf8 --- /dev/null +++ b/docs/tech-specs/document-embeddings-chunk-id.sw.md @@ -0,0 +1,136 @@ +# Kitambulisho cha Sehemu ya Matini (Document Embeddings Chunk ID) + +## Muhtasari + +Hifadhi ya matini ya maandishi kwa sasa huhifadhi matini ya sehemu moja kwa moja katika sehemu ya data ya hifadhi ya vector, na hivyo kurudia data ambayo ipo katika Garage. Hati hii inabadilisha uhifadhi wa matini ya sehemu kwa kutumia marejeleo ya `chunk_id`. + +## Hali ya Sasa + +```python +@dataclass +class ChunkEmbeddings: + chunk: bytes = b"" + vectors: list[list[float]] = field(default_factory=list) + +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunks: list[str] = field(default_factory=list) +``` + +Hifadhi ya data ya aina ya vector: +```python +payload={"doc": chunk} # Duplicates Garage content +``` + +## Ubunifu + +### Mabadiliko ya Mpango + +**ChunkEmbeddings** - badilisha "chunk" na "chunk_id": +```python +@dataclass +class ChunkEmbeddings: + chunk_id: str = "" + vectors: list[list[float]] = field(default_factory=list) +``` + +**Jibu la DocumentEmbeddingsResponse** - irudishe `chunk_ids` badala ya `chunks`: +```python +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunk_ids: list[str] = field(default_factory=list) +``` + +### Mfumo wa Hifadhi ya Vektor + +Maduka yote (Qdrant, Milvus, Pinecone): +```python +payload={"chunk_id": chunk_id} +``` + +### Mabadiliko ya Mchakato wa RAG wa Hati + +Mchakato wa RAG wa hati hupata maudhui ya sehemu kutoka kwa Garage: + +```python +# Get chunk_ids from embeddings store +chunk_ids = await self.rag.doc_embeddings_client.query(...) + +# Fetch chunk content from Garage +docs = [] +for chunk_id in chunk_ids: + content = await self.rag.librarian_client.get_document_content( + chunk_id, self.user + ) + docs.append(content) +``` + +### Mabadiliko ya API/SDK + +**DocumentEmbeddingsClient** hurudia chunk_ids: +```python +return resp.chunk_ids # Changed from resp.chunks +``` + +**Muundo wa data** (Mfasiri wa Majibu ya Matangazo ya Hati): +```python +result["chunk_ids"] = obj.chunk_ids # Changed from chunks +``` + +### Mabadiliko ya CLI + +Zana ya CLI inaonyesha kitambulisho cha vipande (watumiaji wanaweza kupata maudhui kando ikiwa ni lazima). + +## Faili Zinazohitajika Kubadilishwa + +### Mpango (Schema) +`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - ChunkEmbeddings +`trustgraph-base/trustgraph/schema/services/query.py` - DocumentEmbeddingsResponse + +### Ujumbe/Watafsiri +`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - DocumentEmbeddingsResponseTranslator + +### Mteja (Client) +`trustgraph-base/trustgraph/base/document_embeddings_client.py` - rudisha kitambulisho cha vipande + +### SDK/API ya Python +`trustgraph-base/trustgraph/api/flow.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/socket_client.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/async_flow.py` - ikiwa inafaa +`trustgraph-base/trustgraph/api/bulk_client.py` - uagizaji/uangamizi wa vipande vya maandishi +`trustgraph-base/trustgraph/api/async_bulk_client.py` - uagizaji/uangamizi wa vipande vya maandishi + +### Huduma ya Vipande vya Maandishi (Embeddings Service) +`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - pitisha kitambulisho cha kipande + +### Waandishi wa Uhifadhi (Storage Writers) +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` + +### Huduma za Utafutaji (Query Services) +`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py` + +### Lango (Gateway) +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py` + +### Utafutaji wa Hati (Document RAG) +`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - ongeza mteja wa "librarian" +`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - pata kutoka "Garage" + +### CLI +`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py` +`trustgraph-cli/trustgraph/cli/save_doc_embeds.py` +`trustgraph-cli/trustgraph/cli/load_doc_embeds.py` + +## Faida + +1. Chanzo kimoja cha ukweli - maandishi ya vipande tu katika "Garage" +2. Kupunguzwa kwa uhifadhi wa hifadhi ya vector +3. Inawezesha uhakikisho wa muda wa utafutaji kupitia kitambulisho cha kipande. diff --git a/docs/tech-specs/document-embeddings-chunk-id.tr.md b/docs/tech-specs/document-embeddings-chunk-id.tr.md new file mode 100644 index 00000000..ced9a1f2 --- /dev/null +++ b/docs/tech-specs/document-embeddings-chunk-id.tr.md @@ -0,0 +1,136 @@ +# Belge Gömme Parçası Kimliği + +## Genel Bakış + +Belge gömme depolaması şu anda parça metnini doğrudan vektör deposu yüküne kaydederek, Garage'da bulunan verilerin çoğaltılmasına neden oluyor. Bu özellik, parça metni depolamasını `chunk_id` referanslarıyla değiştirmektedir. + +## Mevcut Durum + +```python +@dataclass +class ChunkEmbeddings: + chunk: bytes = b"" + vectors: list[list[float]] = field(default_factory=list) + +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunks: list[str] = field(default_factory=list) +``` + +Vektör depolama yükü: +```python +payload={"doc": chunk} # Duplicates Garage content +``` + +## Tasarım + +### Şema Değişiklikleri + +**ChunkEmbeddings** - chunk'ı chunk_id ile değiştirin: +```python +@dataclass +class ChunkEmbeddings: + chunk_id: str = "" + vectors: list[list[float]] = field(default_factory=list) +``` + +**DocumentEmbeddingsResponse** - parçalar yerine chunk_id'leri döndür: +```python +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunk_ids: list[str] = field(default_factory=list) +``` + +### Vektör Depolama Veri Yapısı + +Tüm depolar (Qdrant, Milvus, Pinecone): +```python +payload={"chunk_id": chunk_id} +``` + +### Belge RAG Değişiklikleri + +Belge RAG işlemcisi, parça içeriğini Garage'dan alır: + +```python +# Get chunk_ids from embeddings store +chunk_ids = await self.rag.doc_embeddings_client.query(...) + +# Fetch chunk content from Garage +docs = [] +for chunk_id in chunk_ids: + content = await self.rag.librarian_client.get_document_content( + chunk_id, self.user + ) + docs.append(content) +``` + +### API/SDK Değişiklikleri + +**DocumentEmbeddingsClient**, `chunk_ids` değerini döndürür: +```python +return resp.chunk_ids # Changed from resp.chunks +``` + +**Kablolu format** (DocumentEmbeddingsResponseTranslator): +```python +result["chunk_ids"] = obj.chunk_ids # Changed from chunks +``` + +### CLI Değişiklikleri + +CLI aracı, chunk_id'leri gösterir (çağrıcılar, gerekirse içeriği ayrı olarak alabilir). + +## Değiştirilecek Dosyalar + +### Şema +`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - ChunkEmbeddings +`trustgraph-base/trustgraph/schema/services/query.py` - DocumentEmbeddingsResponse + +### Mesajlaşma/Çeviriciler +`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - DocumentEmbeddingsResponseTranslator + +### İstemci +`trustgraph-base/trustgraph/base/document_embeddings_client.py` - chunk_id'leri döndür + +### Python SDK/API +`trustgraph-base/trustgraph/api/flow.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/socket_client.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/async_flow.py` - eğer uygunsa +`trustgraph-base/trustgraph/api/bulk_client.py` - belge gömülerinin içe/dışa aktarımı +`trustgraph-base/trustgraph/api/async_bulk_client.py` - belge gömülerinin içe/dışa aktarımı + +### Gömme Hizmeti +`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - chunk_id'yi ilet + +### Depolama Yazıcıları +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` + +### Sorgu Hizmetleri +`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py` + +### Ağ Geçidi +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py` + +### Belge RAG +`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - librarian istemcisini ekle +`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - Garage'dan al + +### CLI +`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py` +`trustgraph-cli/trustgraph/cli/save_doc_embeds.py` +`trustgraph-cli/trustgraph/cli/load_doc_embeds.py` + +## Faydalar + +1. Tek kaynaklı doğruluk - chunk metni yalnızca Garage'da bulunur. +2. Vektör depolama alanında azalma. +3. chunk_id aracılığıyla sorgu zamanı köken bilgisini sağlar. diff --git a/docs/tech-specs/document-embeddings-chunk-id.zh-cn.md b/docs/tech-specs/document-embeddings-chunk-id.zh-cn.md new file mode 100644 index 00000000..53798ca8 --- /dev/null +++ b/docs/tech-specs/document-embeddings-chunk-id.zh-cn.md @@ -0,0 +1,136 @@ +# 文档嵌入块 ID + +## 概述 + +目前,文档嵌入存储将块文本直接存储在向量存储的负载中,这会重复 Garage 中已存在的数据。此规范将块文本存储替换为对 `chunk_id` 的引用。 + +## 当前状态 + +```python +@dataclass +class ChunkEmbeddings: + chunk: bytes = b"" + vectors: list[list[float]] = field(default_factory=list) + +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunks: list[str] = field(default_factory=list) +``` + +向量存储负载: +```python +payload={"doc": chunk} # Duplicates Garage content +``` + +## 设计 + +### 模式变更 + +**ChunkEmbeddings** - 将 chunk 替换为 chunk_id: +```python +@dataclass +class ChunkEmbeddings: + chunk_id: str = "" + vectors: list[list[float]] = field(default_factory=list) +``` + +**DocumentEmbeddingsResponse** - 返回 chunk_ids 而不是 chunks: +```python +@dataclass +class DocumentEmbeddingsResponse: + error: Error | None = None + chunk_ids: list[str] = field(default_factory=list) +``` + +### 向量存储负载 + +所有存储(Qdrant、Milvus、Pinecone): +```python +payload={"chunk_id": chunk_id} +``` + +### 文档 RAG 变更 + +文档 RAG 处理器从 Garage 中获取块内容: + +```python +# Get chunk_ids from embeddings store +chunk_ids = await self.rag.doc_embeddings_client.query(...) + +# Fetch chunk content from Garage +docs = [] +for chunk_id in chunk_ids: + content = await self.rag.librarian_client.get_document_content( + chunk_id, self.user + ) + docs.append(content) +``` + +### API/SDK 变更 + +**DocumentEmbeddingsClient** 返回 chunk_ids: +```python +return resp.chunk_ids # Changed from resp.chunks +``` + +**数据格式** (DocumentEmbeddingsResponseTranslator): +```python +result["chunk_ids"] = obj.chunk_ids # Changed from chunks +``` + +### CLI 变更 + +CLI 工具显示 chunk_ids(如果需要,调用者可以单独获取内容)。 + +## 需要修改的文件 + +### Schema +`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - ChunkEmbeddings +`trustgraph-base/trustgraph/schema/services/query.py` - DocumentEmbeddingsResponse + +### 消息/翻译器 +`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - DocumentEmbeddingsResponseTranslator + +### 客户端 +`trustgraph-base/trustgraph/base/document_embeddings_client.py` - 返回 chunk_ids + +### Python SDK/API +`trustgraph-base/trustgraph/api/flow.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/socket_client.py` - document_embeddings_query +`trustgraph-base/trustgraph/api/async_flow.py` - 如果适用 +`trustgraph-base/trustgraph/api/bulk_client.py` - 导入/导出文档嵌入 +`trustgraph-base/trustgraph/api/async_bulk_client.py` - 导入/导出文档嵌入 + +### 嵌入服务 +`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - 传递 chunk_id + +### 存储写入器 +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` + +### 查询服务 +`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py` +`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py` + +### 网关 +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py` +`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py` + +### 文档 RAG +`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - 添加 librarian 客户端 +`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - 从 Garage 获取 + +### CLI +`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py` +`trustgraph-cli/trustgraph/cli/save_doc_embeds.py` +`trustgraph-cli/trustgraph/cli/load_doc_embeds.py` + +## 优点 + +1. 单一数据源 - 仅在 Garage 中存储文本块 +2. 减少向量存储空间 +3. 通过 chunk_id 实现查询时的数据溯源 diff --git a/docs/tech-specs/embeddings-batch-processing.ar.md b/docs/tech-specs/embeddings-batch-processing.ar.md new file mode 100644 index 00000000..76720dcb --- /dev/null +++ b/docs/tech-specs/embeddings-batch-processing.ar.md @@ -0,0 +1,667 @@ +# المواصفات الفنية لمعالجة الدفعات لخدمة التضمينات (Embeddings) + +## نظرة عامة + +تصف هذه المواصفات التحسينات التي ستُجرى على خدمة التضمينات لدعم معالجة الدفعات لعدد كبير من النصوص في طلب واحد. تعالج التنفيذ الحالي النص الواحد في كل مرة، مما يفوّت المزايا الكبيرة في الأداء التي توفرها نماذج التضمين عند معالجة الدفعات. + +1. **عدم كفاءة معالجة النصوص الفردية**: يغلف التنفيذ الحالي النصوص الفردية في قائمة، مما يؤدي إلى عدم الاستفادة الكاملة من قدرات الدفعات في FastEmbed. +2. **العبء الزائد لكل طلب نص**: يتطلب كل نص رسالة Pulsar منفصلة، مما يتطلب جولة ذهاب وإياب. +3. **عدم كفاءة استنتاج النموذج**: نماذج التضمين لها عبء ثابت لكل دفعة؛ فإن الدفعات الصغيرة تهدر موارد وحدة معالجة الرسومات (GPU) ووحدة المعالجة المركزية (CPU). +4. **المعالجة التسلسلية في التطبيقات**: تقوم الخدمات الرئيسية بالتكرار على العناصر واستدعاء التضمينات واحدًا تلو الآخر. + +## الأهداف + +**دعم واجهة برمجة تطبيقات (API) للدفعات**: تمكين معالجة نصوص متعددة في طلب واحد. +**التوافق مع الإصدارات السابقة**: الحفاظ على دعم الطلبات التي تتضمن نصًا واحدًا فقط. +**تحسين كبير في الإنتاجية**: استهداف تحسين في الإنتاجية يتراوح بين 5 إلى 10 مرات للعمليات الجماعية. +**تقليل زمن الوصول لكل نص**: تقليل زمن الوصول المتوسط عند تضمين نصوص متعددة. +**كفاءة الذاكرة**: معالجة الدفعات دون استهلاك مفرط للذاكرة. +**الاستقلالية عن المزود**: دعم التجميع عبر FastEmbed و Ollama ومزودين آخرين. +**تحديث التطبيقات**: تحديث جميع تطبيقات التضمين لاستخدام واجهة برمجة تطبيقات الدفعات عند الإمكان. + +## الخلفية + +### التنفيذ الحالي - خدمة التضمينات + +يُظهر تطبيق التضمينات في `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` عدم كفاءة كبيرة في الأداء: + +```python +# fastembed/processor.py line 56 +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + + vecs = self.embeddings.embed([text]) # Single text wrapped in list + + return [v.tolist() for v in vecs] +``` + +**المشاكل:** + +1. **حجم الدفعة 1**: طريقة `embed()` في FastEmbed مُحسّنة للمعالجة الدفعية، ولكننا نستدعيها دائمًا مع `[text]` - دفعة بحجم 1. + +2. **التكلفة لكل طلب**: كل طلب تضمين يتضمن: + تسلسل/إلغاء تسلسل رسالة Pulsar. + زمن انتقال الشبكة. + تكلفة بدء تشغيل الاستدلال للنموذج. + تكلفة جدولة المهام غير المتزامنة في Python. + +3. **قيود المخطط**: مخطط `EmbeddingsRequest` يدعم نصًا واحدًا فقط: + ```python + @dataclass + class EmbeddingsRequest: + text: str = "" # Single text only + ``` + +### المستخدمون الحاليون - المعالجة التسلسلية + +#### 1. بوابة واجهة برمجة التطبيقات (API Gateway) + +**الملف:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +تقبل البوابة طلبات تضمين النصوص الفردية عبر HTTP/WebSocket وتوجهها إلى خدمة التضمين. حاليًا، لا يوجد نقطة نهاية للدفعات. + +```python +class EmbeddingsRequestor(ServiceRequestor): + # Handles single EmbeddingsRequest -> EmbeddingsResponse + request_schema=EmbeddingsRequest, # Single text only + response_schema=EmbeddingsResponse, +``` + +**التأثير:** يجب على العملاء الخارجيين (تطبيقات الويب، النصوص البرمجية) إجراء N طلب HTTP لتضمين N نص. + +#### 2. خدمة تضمين المستندات + +**الملف:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +يعالج أجزاء المستندات واحدة تلو الأخرى: + +```python +async def on_message(self, msg, consumer, flow): + v = msg.value() + + # Single chunk per request + resp = await flow("embeddings-request").request( + EmbeddingsRequest(text=v.chunk) + ) + vectors = resp.vectors +``` + +**التأثير:** تتطلب كل جزء من المستند استدعاءً منفصلاً لعملية التضمين. المستند الذي يتكون من 100 جزء = 100 طلب تضمين. + +#### 3. خدمة تضمين الرسوم البيانية + +**الملف:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + +يتكرر على الكيانات ويقوم بتضمين كل منها بالتسلسل: + +```python +async def on_message(self, msg, consumer, flow): + for entity in v.entities: + # Serial embedding - one entity at a time + vectors = await flow("embeddings-request").embed( + text=entity.context + ) + entities.append(EntityEmbeddings( + entity=entity.entity, + vectors=vectors, + chunk_id=entity.chunk_id, + )) +``` + +**التأثير:** رسالة تحتوي على 50 كيانًا = 50 طلب تضمين تسلسلي. هذا يمثل عنق زجاجة رئيسي أثناء بناء الرسم البياني المعرفي. + +#### 4. خدمة تضمين الصفوف + +**الملف:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + +يتكرر على النصوص الفريدة ويضمّن كل منها بشكل تسلسلي: + +```python +async def on_message(self, msg, consumer, flow): + for text, (index_name, index_value) in texts_to_embed.items(): + # Serial embedding - one text at a time + vectors = await flow("embeddings-request").embed(text=text) + + embeddings_list.append(RowIndexEmbedding( + index_name=index_name, + index_value=index_value, + text=text, + vectors=vectors + )) +``` + +**التأثير:** معالجة جدول يحتوي على 100 قيمة فريدة مفهرسة = 100 طلب تضمين متسلسل. + +#### 5. EmbeddingsClient (العميل الأساسي) + +**الملف:** `trustgraph-base/trustgraph/base/embeddings_client.py` + +العميل المستخدم من قبل جميع معالجات التدفق يدعم فقط تضمين النصوص الفردية: + +```python +class EmbeddingsClient(RequestResponse): + async def embed(self, text, timeout=30): + resp = await self.request( + EmbeddingsRequest(text=text), # Single text + timeout=timeout + ) + return resp.vectors +``` + +**التأثير:** جميع المستخدمين الذين يعتمدون على هذا البرنامج يقتصرون على العمليات النصية البسيطة. + +#### 6. أدوات سطر الأوامر + +**الملف:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +أداة سطر الأوامر تقبل وسيط نصي واحد: + +```python +def query(url, flow_id, text, token=None): + result = flow.embeddings(text=text) # Single text + vectors = result.get("vectors", []) +``` + +**التأثير:** لا يمكن للمستخدمين إجراء تضمين مجمّع من سطر الأوامر. يتطلب معالجة ملف من النصوص عدد N من الاستدعاءات. + +#### 7. حزمة تطوير البرمجيات (SDK) الخاصة بـ Python + +توفر حزمة تطوير البرمجيات الخاصة بـ Python فئتين من العملاء للتفاعل مع خدمات TrustGraph. تدعم كلتاهما فقط التضمين لنص واحد. + +**الملف:** `trustgraph-base/trustgraph/api/flow.py` + +```python +class FlowInstance: + def embeddings(self, text): + """Get embeddings for a single text""" + input = {"text": text} + return self.request("service/embeddings", input)["vectors"] +``` + +**الملف:** `trustgraph-base/trustgraph/api/socket_client.py` + +```python +class SocketFlowInstance: + def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]: + """Get embeddings for a single text via WebSocket""" + request = {"text": text} + return self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) +``` + +**التأثير:** يجب على مطوري بايثون الذين يستخدمون مجموعة تطوير البرامج (SDK) المرور على النصوص وإجراء مكالمات واجهة برمجة التطبيقات (API) منفصلة. لا يوجد دعم لعمليات الدمج المجمعة لمستخدمي مجموعة تطوير البرامج. + +### تأثير الأداء + +بالنسبة لاستيعاب المستندات النموذجي (1000 جزء نصي): +**الحالي:** 1000 طلب منفصل، و1000 استدعاء لنموذج الاستدلال. +**مجمعة (batch_size=32):** 32 طلبًا، و32 استدعاء لنموذج الاستدلال (انخفاض بنسبة 96.8٪). + +بالنسبة لدمج الرسم البياني (رسالة تحتوي على 50 كيانًا): +**الحالي:** 50 استدعاء انتظار متسلسل، من 5 إلى 10 ثوانٍ تقريبًا. +**مجمعة:** 1-2 استدعاء مجمع، من 0.5 إلى 1 ثانية تقريبًا (تحسين بمقدار 5-10 مرات). + +تحقق مكتبات FastEmbed والمكتبات المماثلة تقريبًا من قابلية التوسع الخطية في الإنتاجية مع حجم الدفعة حتى حدود الأجهزة (عادةً ما تكون 32-128 نصًا لكل دفعة). + +## التصميم الفني + +### البنية + +يتطلب تحسين معالجة الدفعات لإنشاء تضمينات تغييرات في المكونات التالية: + +#### 1. **تحسين المخطط** + قم بتوسيع `EmbeddingsRequest` لدعم نصوص متعددة. + قم بتوسيع `EmbeddingsResponse` لإرجاع مجموعات متجهات متعددة. + حافظ على التوافق مع الإصدارات السابقة مع طلبات النص الواحد. + + الوحدة: `trustgraph-base/trustgraph/schema/services/llm.py` + +#### 2. **تحسين الخدمة الأساسية** + قم بتحديث `EmbeddingsService` للتعامل مع الطلبات المجمعة. + أضف تكوين حجم الدفعة. + قم بتنفيذ معالجة الطلبات الواعية بالدفعة. + + الوحدة: `trustgraph-base/trustgraph/base/embeddings_service.py` + +#### 3. **تحديثات معالج المزود** + قم بتحديث معالج FastEmbed لتمرير الدفعة الكاملة إلى `embed()`. + قم بتحديث معالج Ollama للتعامل مع الدفعات (إذا تم الدعم). + أضف معالجة تسلسلية احتياطية للمزودين الذين لا يدعمون الدفعات. + + الوحدات: + `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` + `trustgraph-flow/trustgraph/embeddings/ollama/processor.py` + +#### 4. **تحسين العميل** + أضف طريقة إنشاء تضمينات مجمعة إلى `EmbeddingsClient`. + دعم كل من واجهات برمجة التطبيقات الفردية والمجمعة. + أضف تجميعًا تلقائيًا للمدخلات الكبيرة. + + الوحدة: `trustgraph-base/trustgraph/base/embeddings_client.py` + +#### 5. **تحديثات المتصل - معالجات التدفق** + قم بتحديث `graph_embeddings` لتجميع سياقات الكيانات. + قم بتحديث `row_embeddings` لتجميع نصوص الفهرس. + قم بتحديث `document_embeddings` إذا كان تجميع الرسائل ممكنًا. + + الوحدات: + `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +#### 6. **تحسين بوابة واجهة برمجة التطبيقات** + أضف نقطة نهاية لإنشاء تضمينات مجمعة. + دعم مصفوفة من النصوص في نص الطلب. + + الوحدة: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +#### 7. **تحسين أداة سطر الأوامر** + أضف دعمًا للنصوص المتعددة أو إدخال الملف. + أضف معلمة حجم الدفعة. + + الوحدة: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +#### 8. **تحسين مجموعة تطوير البرامج (SDK) الخاصة بـ Python** + أضف طريقة `embeddings_batch()` إلى `FlowInstance`. + أضف طريقة `embeddings_batch()` إلى `SocketFlowInstance`. + دعم كل من واجهات برمجة التطبيقات الفردية والمجمعة لمستخدمي مجموعة تطوير البرامج. + + الوحدات: + `trustgraph-base/trustgraph/api/flow.py` + `trustgraph-base/trustgraph/api/socket_client.py` + +### نماذج البيانات + +#### EmbeddingsRequest + +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +الاستخدام: +نص مفرد: `EmbeddingsRequest(texts=["hello world"])` +دفعة: `EmbeddingsRequest(texts=["text1", "text2", "text3"])` + +#### EmbeddingsResponse + +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +هيكل الاستجابة: +`vectors[i]` يحتوي على مجموعة المتجهات لـ `texts[i]` +كل مجموعة متجهات هي `list[list[float]]` (قد تُرجع النماذج عدة متجهات لكل نص) +مثال: 3 نصوص → `vectors` يحتوي على 3 إدخالات، كل منها يحتوي على تضمينات هذا النص + +### واجهات برمجة التطبيقات (APIs) + +#### EmbeddingsClient + +```python +class EmbeddingsClient(RequestResponse): + async def embed( + self, + texts: list[str], + timeout: float = 300, + ) -> list[list[list[float]]]: + """ + Embed one or more texts in a single request. + + Args: + texts: List of texts to embed + timeout: Timeout for the operation + + Returns: + List of vector sets, one per input text + """ + resp = await self.request( + EmbeddingsRequest(texts=texts), + timeout=timeout + ) + if resp.error: + raise RuntimeError(resp.error.message) + return resp.vectors +``` + +#### نقطة نهاية تضمين بوابة واجهة برمجة التطبيقات (API Gateway). + +تم تحديث نقطة النهاية لدعم التضمين الفردي أو الدفعي: + +``` +POST /api/v1/embeddings +Content-Type: application/json + +{ + "texts": ["text1", "text2", "text3"], + "flow_id": "default" +} + +Response: +{ + "vectors": [ + [[0.1, 0.2, ...]], + [[0.3, 0.4, ...]], + [[0.5, 0.6, ...]] + ] +} +``` + +### تفاصيل التنفيذ + +#### المرحلة الأولى: تغييرات المخطط + +**EmbeddingsRequest:** +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +**الاستجابة المضمنة:** +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +**تم تحديث `EmbeddingsService.on_request`:** +```python +async def on_request(self, msg, consumer, flow): + request = msg.value() + id = msg.properties()["id"] + model = flow("model") + + vectors = await self.on_embeddings(request.texts, model=model) + response = EmbeddingsResponse(error=None, vectors=vectors) + + await flow("response").send(response, properties={"id": id}) +``` + +#### المرحلة الثانية: تحديث معالج FastEmbed + +**الحالي (غير فعال):** +```python +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + vecs = self.embeddings.embed([text]) # Batch of 1 + return [v.tolist() for v in vecs] +``` + +**تحديث:** +```python +async def on_embeddings(self, texts: list[str], model=None): + """Embed texts - processes all texts in single model call""" + if not texts: + return [] + + use_model = model or self.default_model + self._load_model(use_model) + + # FastEmbed handles the full batch efficiently + all_vecs = list(self.embeddings.embed(texts)) + + # Return list of vector sets, one per input text + return [[v.tolist()] for v in all_vecs] +``` + +#### المرحلة الثالثة: تحديث خدمة تضمين الرسوم البيانية + +**الحالي (التسلسلي):** +```python +async def on_message(self, msg, consumer, flow): + entities = [] + for entity in v.entities: + vectors = await flow("embeddings-request").embed(text=entity.context) + entities.append(EntityEmbeddings(...)) +``` + +**تحديث (مجموعة):** +```python +async def on_message(self, msg, consumer, flow): + # Collect all contexts + contexts = [entity.context for entity in v.entities] + + # Single batch embedding call + all_vectors = await flow("embeddings-request").embed(texts=contexts) + + # Pair results with entities + entities = [ + EntityEmbeddings( + entity=entity.entity, + vectors=vectors[0], # First vector from the set + chunk_id=entity.chunk_id, + ) + for entity, vectors in zip(v.entities, all_vectors) + ] +``` + +#### المرحلة الرابعة: تحديث خدمة تضمين الصفوف + +**الحالي (تسلسلي):** +```python +for text, (index_name, index_value) in texts_to_embed.items(): + vectors = await flow("embeddings-request").embed(text=text) + embeddings_list.append(RowIndexEmbedding(...)) +``` + +**تحديث (مجموعة):** +```python +# Collect texts and metadata +texts = list(texts_to_embed.keys()) +metadata = list(texts_to_embed.values()) + +# Single batch embedding call +all_vectors = await flow("embeddings-request").embed(texts=texts) + +# Pair results +embeddings_list = [ + RowIndexEmbedding( + index_name=meta[0], + index_value=meta[1], + text=text, + vectors=vectors[0] # First vector from the set + ) + for text, meta, vectors in zip(texts, metadata, all_vectors) +] +``` + +#### المرحلة الخامسة: تحسين أداة سطر الأوامر. + +**سطر الأوامر المحدث:** +```python +def main(): + parser = argparse.ArgumentParser(...) + + parser.add_argument( + 'text', + nargs='*', # Zero or more texts + help='Text(s) to convert to embedding vectors', + ) + + parser.add_argument( + '-f', '--file', + help='File containing texts (one per line)', + ) + + parser.add_argument( + '--batch-size', + type=int, + default=32, + help='Batch size for processing (default: 32)', + ) +``` + +الاستخدام: +```bash +# Single text (existing) +tg-invoke-embeddings "hello world" + +# Multiple texts +tg-invoke-embeddings "text one" "text two" "text three" + +# From file +tg-invoke-embeddings -f texts.txt --batch-size 64 +``` + +#### المرحلة السادسة: تحسين حزمة تطوير البرمجيات (SDK) الخاصة بـ Python + +**FlowInstance (عميل HTTP):** + +```python +class FlowInstance: + def embeddings(self, texts: list[str]) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + input = {"texts": texts} + return self.request("service/embeddings", input)["vectors"] +``` + +**مثيل SocketFlow (عميل WebSocket):** + +```python +class SocketFlowInstance: + def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts via WebSocket. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + request = {"texts": texts} + response = self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) + return response["vectors"] +``` + +**أمثلة على استخدام الـ SDK:** + +```python +# Single text +vectors = flow.embeddings(["hello world"]) +print(f"Dimensions: {len(vectors[0][0])}") + +# Batch embedding +texts = ["text one", "text two", "text three"] +all_vectors = flow.embeddings(texts) + +# Process results +for text, vecs in zip(texts, all_vectors): + print(f"{text}: {len(vecs[0])} dimensions") +``` + +## اعتبارات الأمان + +**حدود حجم الطلب**: فرض الحد الأقصى لحجم الدفعة لمنع استنزاف الموارد. +**معالجة انتهاء المهلة**: قم بتعيين قيم انتهاء المهلة بشكل مناسب لحجم الدفعة. +**حدود الذاكرة**: راقب استخدام الذاكرة للدفعات الكبيرة. +**التحقق من صحة الإدخال**: تحقق من صحة جميع النصوص في الدفعة قبل المعالجة. + +## اعتبارات الأداء + +### التحسينات المتوقعة + +**معدل الإنتاجية:** +نص واحد: ~10-50 نصًا/ثانية (حسب النموذج) +دفعة (حجم 32): ~200-500 نص/ثانية (تحسين بمقدار 5-10 مرات) + +**زمن الوصول لكل نص:** +نص واحد: 50-200 مللي ثانية لكل نص +دفعة (حجم 32): 5-20 مللي ثانية لكل نص (متوسط) + +**التحسينات الخاصة بالخدمة:** + +| الخدمة | الحالي | الدفعات | التحسين | +|---------|---------|---------|-------------| +| تضمينات الرسم البياني (50 كيانًا) | 5-10 ثوانٍ | 0.5-1 ثانية | 5-10 مرات | +| تضمينات الصفوف (100 نص) | 10-20 ثانية | 1-2 ثانية | 5-10 مرات | +| استيعاب المستندات (1000 جزء) | 100-200 ثانية | 10-30 ثانية | 5-10 مرات | + +### معلمات التكوين + +```python +# Recommended defaults +DEFAULT_BATCH_SIZE = 32 +MAX_BATCH_SIZE = 128 +BATCH_TIMEOUT_MULTIPLIER = 2.0 +``` + +## استراتيجية الاختبار + +### اختبار الوحدات +تضمين نص واحد (التوافق مع الإصدارات السابقة) +معالجة الدُفعات الفارغة +فرض الحد الأقصى لحجم الدفعة +معالجة الأخطاء في حالة فشل بعض عناصر الدفعة + +### اختبار التكامل +تضمين الدُفعات من البداية إلى النهاية عبر Pulsar +معالجة الدُفعات لخدمة تضمينات الرسم البياني +معالجة الدُفعات لخدمة تضمينات الصفوف +نقطة نهاية الدُفعات لبوابة واجهة برمجة التطبيقات + +### اختبار الأداء +قياس الإنتاجية الفردية مقابل الإنتاجية عند استخدام الدُفعات +استخدام الذاكرة تحت أحجام دفعات مختلفة +تحليل توزيع زمن الاستجابة + +## خطة الترحيل + +هذا إصدار يتضمن تغييرات جذرية. يتم تنفيذ جميع المراحل معًا. + +### المرحلة الأولى: تغييرات المخطط +استبدال `text: str` بـ `texts: list[str]` في EmbeddingsRequest +تغيير نوع `vectors` إلى `list[list[list[float]]]` في EmbeddingsResponse + +### المرحلة الثانية: تحديثات المعالج +تحديث توقيع `on_embeddings` في معالجات FastEmbed و Ollama +معالجة الدفعة بأكملها في استدعاء واحد للنموذج + +### المرحلة الثالثة: تحديثات العميل +تحديث `EmbeddingsClient.embed()` لقبول `texts: list[str]` + +### المرحلة الرابعة: تحديثات المستخدم +تحديث graph_embeddings لمعالجة سياقات الكيانات على شكل دفعات +تحديث row_embeddings لمعالجة نصوص الفهرس على شكل دفعات +تحديث document_embeddings لاستخدام المخطط الجديد +تحديث أداة سطر الأوامر + +### المرحلة الخامسة: بوابة واجهة برمجة التطبيقات +تحديث نقطة نهاية تضمين للمخطط الجديد + +### المرحلة السادسة: حزمة تطوير البرمجيات بلغة بايثون +تحديث توقيع `FlowInstance.embeddings()` +تحديث توقيع `SocketFlowInstance.embeddings()` + +## أسئلة مفتوحة + +**معالجة الدُفعات الكبيرة جدًا**: هل يجب أن ندعم إرجاع النتائج على شكل دفعات صغيرة جدًا للدُفعات الكبيرة جدًا (أكثر من 100 نص)؟ +**القيود الخاصة بالمزودين**: كيف يجب أن نتعامل مع المزودين الذين لديهم أحجام دفعات قصوى مختلفة؟ +**معالجة حالات الفشل الجزئية**: إذا فشل أحد النصوص في الدفعة، فهل يجب أن نفشل الدفعة بأكملها أم أن نرجع النتائج الجزئية؟ +**تجميع تضمينات المستندات**: هل يجب أن نقوم بتجميع البيانات عبر رسائل Chunk متعددة أم أن نحافظ على المعالجة لكل رسالة؟ + +## المراجع + +[وثائق FastEmbed](https://github.com/qdrant/fastembed) +[واجهة برمجة تطبيقات Ollama Embeddings](https://github.com/ollama/ollama) +[تنفيذ EmbeddingsService](trustgraph-base/trustgraph/base/embeddings_service.py) +[تحسين أداء GraphRAG](graphrag-performance-optimization.md) diff --git a/docs/tech-specs/embeddings-batch-processing.es.md b/docs/tech-specs/embeddings-batch-processing.es.md new file mode 100644 index 00000000..208d3a85 --- /dev/null +++ b/docs/tech-specs/embeddings-batch-processing.es.md @@ -0,0 +1,667 @@ +# Especificación Técnica del Procesamiento por Lotes de Embeddings + +## Resumen + +Esta especificación describe optimizaciones para el servicio de embeddings para soportar el procesamiento por lotes de múltiples textos en una sola solicitud. La implementación actual procesa un texto a la vez, perdiendo las significativas ventajas de rendimiento que los modelos de embeddings proporcionan al procesar lotes. + +1. **Ineficiencia en el Procesamiento de un Solo Texto**: La implementación actual envuelve textos individuales en una lista, lo que no aprovecha las capacidades de procesamiento por lotes de FastEmbed. +2. **Sobrecarga de una Solicitud por Texto**: Cada texto requiere un viaje de ida y vuelta separado de Pulsar. +3. **Ineficiencia en la Inferencia del Modelo**: Los modelos de embeddings tienen una sobrecarga fija por lote; los lotes pequeños desperdician recursos de GPU/CPU. +4. **Procesamiento Serial en los Llamadores**: Los servicios clave iteran sobre los elementos y llaman a los embeddings uno a la vez. + +## Objetivos + +**Soporte para la API de Lotes**: Permitir el procesamiento de múltiples textos en una sola solicitud. +**Compatibilidad con Versiones Anteriores**: Mantener el soporte para solicitudes de un solo texto. +**Mejora Significativa del Rendimiento**: Apuntar a una mejora de rendimiento de 5 a 10 veces para operaciones por lotes. +**Latencia Reducida por Texto**: Disminuir la latencia amortizada al incrustar múltiples textos. +**Eficiencia de Memoria**: Procesar lotes sin un consumo excesivo de memoria. +**Independencia del Proveedor**: Soporte para el procesamiento por lotes en FastEmbed, Ollama y otros proveedores. +**Migración de Llamadores**: Actualizar todos los llamadores de embeddings para que utilicen la API de lotes cuando sea beneficioso. + +## Antecedentes + +### Implementación Actual - Servicio de Embeddings + +La implementación de embeddings en `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` presenta una ineficiencia de rendimiento significativa: + +```python +# fastembed/processor.py line 56 +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + + vecs = self.embeddings.embed([text]) # Single text wrapped in list + + return [v.tolist() for v in vecs] +``` + +**Problemas:** + +1. **Tamaño de lote 1**: El método `embed()` de FastEmbed está optimizado para el procesamiento por lotes, pero siempre lo llamamos con `[text]`, un lote de tamaño 1. + +2. **Sobrecarga por solicitud**: Cada solicitud de incrustación incurre en: + Serialización/deserialización de mensajes de Pulsar + Latencia de ida y vuelta de la red + Sobrecarga de inicio de inferencia del modelo + Sobrecarga de programación asíncrona de Python + +3. **Limitación del esquema**: El esquema `EmbeddingsRequest` solo admite un texto: + ```python + @dataclass + class EmbeddingsRequest: + text: str = "" # Single text only + ``` + +### Llamadores actuales - Procesamiento serial + +#### 1. API Gateway + +**Archivo:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +La puerta de enlace acepta solicitudes de incrustación de texto único a través de HTTP/WebSocket y las reenvía al servicio de incrustaciones. Actualmente no existe un punto final por lotes. + +```python +class EmbeddingsRequestor(ServiceRequestor): + # Handles single EmbeddingsRequest -> EmbeddingsResponse + request_schema=EmbeddingsRequest, # Single text only + response_schema=EmbeddingsResponse, +``` + +**Impacto:** Los clientes externos (aplicaciones web, scripts) deben realizar N solicitudes HTTP para incrustar N textos. + +#### 2. Servicio de Incorporación de Documentos + +**Archivo:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +Procesa fragmentos de documentos uno a la vez: + +```python +async def on_message(self, msg, consumer, flow): + v = msg.value() + + # Single chunk per request + resp = await flow("embeddings-request").request( + EmbeddingsRequest(text=v.chunk) + ) + vectors = resp.vectors +``` + +**Impacto:** Cada fragmento de documento requiere una llamada de incrustación separada. Un documento con 100 fragmentos = 100 solicitudes de incrustación. + +#### 3. Servicio de Incrustaciones de Grafos + +**Archivo:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + +Recorre las entidades e incrusta cada una de forma secuencial: + +```python +async def on_message(self, msg, consumer, flow): + for entity in v.entities: + # Serial embedding - one entity at a time + vectors = await flow("embeddings-request").embed( + text=entity.context + ) + entities.append(EntityEmbeddings( + entity=entity.entity, + vectors=vectors, + chunk_id=entity.chunk_id, + )) +``` + +**Impacto:** Un mensaje con 50 entidades = 50 solicitudes de incrustación serial. Esto es un cuello de botella importante durante la construcción del grafo de conocimiento. + +#### 4. Servicio de Incrustaciones de Filas + +**Archivo:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + +Itera sobre textos únicos e incrusta cada uno de forma serial: + +```python +async def on_message(self, msg, consumer, flow): + for text, (index_name, index_value) in texts_to_embed.items(): + # Serial embedding - one text at a time + vectors = await flow("embeddings-request").embed(text=text) + + embeddings_list.append(RowIndexEmbedding( + index_name=index_name, + index_value=index_value, + text=text, + vectors=vectors + )) +``` + +**Impacto:** Procesar una tabla con 100 valores indexados únicos = 100 solicitudes de incrustación seriales. + +#### 5. EmbeddingsClient (Cliente Base) + +**Archivo:** `trustgraph-base/trustgraph/base/embeddings_client.py` + +El cliente utilizado por todos los procesadores de flujo solo admite la incrustación de texto único: + +```python +class EmbeddingsClient(RequestResponse): + async def embed(self, text, timeout=30): + resp = await self.request( + EmbeddingsRequest(text=text), # Single text + timeout=timeout + ) + return resp.vectors +``` + +**Impacto:** Todos los clientes que utilizan esta herramienta están limitados a operaciones de texto único. + +#### 6. Herramientas de Línea de Comandos + +**Archivo:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +La herramienta de la línea de comandos acepta un único argumento de texto: + +```python +def query(url, flow_id, text, token=None): + result = flow.embeddings(text=text) # Single text + vectors = result.get("vectors", []) +``` + +**Impacto:** Los usuarios no pueden realizar incrustaciones por lotes desde la línea de comandos. El procesamiento de un archivo de textos requiere N invocaciones. + +#### 7. SDK de Python + +El SDK de Python proporciona dos clases de cliente para interactuar con los servicios de TrustGraph. Ambas solo admiten la incrustación de un solo texto. + +**Archivo:** `trustgraph-base/trustgraph/api/flow.py` + +```python +class FlowInstance: + def embeddings(self, text): + """Get embeddings for a single text""" + input = {"text": text} + return self.request("service/embeddings", input)["vectors"] +``` + +**Archivo:** `trustgraph-base/trustgraph/api/socket_client.py` + +```python +class SocketFlowInstance: + def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]: + """Get embeddings for a single text via WebSocket""" + request = {"text": text} + return self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) +``` + +**Impacto:** Los desarrolladores de Python que utilizan el SDK deben iterar sobre los textos y realizar N llamadas de API separadas. No existe soporte para la inserción por lotes para los usuarios del SDK. + +### Impacto en el rendimiento + +Para la ingestión típica de documentos (1000 fragmentos de texto): +**Actual:** 1000 solicitudes separadas, 1000 llamadas de inferencia de modelos. +**Por lotes (batch_size=32):** 32 solicitudes, 32 llamadas de inferencia de modelos (reducción del 96.8%). + +Para la inserción de gráficos (mensaje con 50 entidades): +**Actual:** 50 llamadas `await` secuenciales, ~5-10 segundos. +**Por lotes:** 1-2 llamadas por lotes, ~0.5-1 segundo (mejora de 5-10 veces). + +FastEmbed y bibliotecas similares logran una escalabilidad de rendimiento cercana a la lineal con el tamaño del lote hasta los límites del hardware (típicamente 32-128 textos por lote). + +## Diseño técnico + +### Arquitectura + +La optimización del procesamiento por lotes de inserciones requiere cambios en los siguientes componentes: + +#### 1. **Mejora del esquema** + Extender `EmbeddingsRequest` para admitir múltiples textos. + Extender `EmbeddingsResponse` para devolver múltiples conjuntos de vectores. + Mantener la compatibilidad con versiones anteriores con solicitudes de un solo texto. + + Módulo: `trustgraph-base/trustgraph/schema/services/llm.py` + +#### 2. **Mejora del servicio base** + Actualizar `EmbeddingsService` para manejar solicitudes por lotes. + Agregar configuración del tamaño del lote. + Implementar el manejo de solicitudes con conocimiento del lote. + + Módulo: `trustgraph-base/trustgraph/base/embeddings_service.py` + +#### 3. **Actualizaciones del procesador del proveedor** + Actualizar el procesador FastEmbed para pasar el lote completo a `embed()`. + Actualizar el procesador de Ollama para manejar lotes (si es compatible). + Agregar procesamiento secuencial de respaldo para los proveedores que no admiten lotes. + + Módulos: + `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` + `trustgraph-flow/trustgraph/embeddings/ollama/processor.py` + +#### 4. **Mejora del cliente** + Agregar un método de inserción por lotes a `EmbeddingsClient`. + Admitir tanto API individuales como por lotes. + Agregar inserción automática por lotes para grandes entradas. + + Módulo: `trustgraph-base/trustgraph/base/embeddings_client.py` + +#### 5. **Actualizaciones del llamador: Procesadores de flujo** + Actualizar `graph_embeddings` para agrupar los contextos de las entidades. + Actualizar `row_embeddings` para agrupar los textos del índice. + Actualizar `document_embeddings` si el agrupamiento de mensajes es factible. + + Módulos: + `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +#### 6. **Mejora de la puerta de enlace de API** + Agregar un punto final de inserción por lotes. + Admitir una matriz de textos en el cuerpo de la solicitud. + + Módulo: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +#### 7. **Mejora de la herramienta de la línea de comandos** + Agregar soporte para múltiples textos o entrada de archivos. + Agregar un parámetro de tamaño de lote. + + Módulo: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +#### 8. **Mejora del SDK de Python** + Agregar el método `embeddings_batch()` a `FlowInstance`. + Agregar el método `embeddings_batch()` a `SocketFlowInstance`. + Admitir tanto API individuales como por lotes para los usuarios del SDK. + + Módulos: + `trustgraph-base/trustgraph/api/flow.py` + `trustgraph-base/trustgraph/api/socket_client.py` + +### Modelos de datos + +#### EmbeddingsRequest + +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +Uso: +Texto único: `EmbeddingsRequest(texts=["hello world"])` +Lote: `EmbeddingsRequest(texts=["text1", "text2", "text3"])` + +#### EmbeddingsResponse + +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +Estructura de la respuesta: +`vectors[i]` contiene el conjunto de vectores para `texts[i]` +Cada conjunto de vectores es `list[list[float]]` (los modelos pueden devolver múltiples vectores por texto) +Ejemplo: 3 textos → `vectors` tiene 3 entradas, cada una conteniendo los incrustados de ese texto + +### APIs + +#### EmbeddingsClient + +```python +class EmbeddingsClient(RequestResponse): + async def embed( + self, + texts: list[str], + timeout: float = 300, + ) -> list[list[list[float]]]: + """ + Embed one or more texts in a single request. + + Args: + texts: List of texts to embed + timeout: Timeout for the operation + + Returns: + List of vector sets, one per input text + """ + resp = await self.request( + EmbeddingsRequest(texts=texts), + timeout=timeout + ) + if resp.error: + raise RuntimeError(resp.error.message) + return resp.vectors +``` + +#### Punto final de incrustaciones de la API Gateway + +Punto final actualizado que admite incrustaciones individuales o por lotes: + +``` +POST /api/v1/embeddings +Content-Type: application/json + +{ + "texts": ["text1", "text2", "text3"], + "flow_id": "default" +} + +Response: +{ + "vectors": [ + [[0.1, 0.2, ...]], + [[0.3, 0.4, ...]], + [[0.5, 0.6, ...]] + ] +} +``` + +### Detalles de implementación + +#### Fase 1: Cambios en el esquema + +**EmbeddingsRequest:** +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +**Respuesta de Inserción:** +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +**Actualizaciones en EmbeddingsService.on_request:** +```python +async def on_request(self, msg, consumer, flow): + request = msg.value() + id = msg.properties()["id"] + model = flow("model") + + vectors = await self.on_embeddings(request.texts, model=model) + response = EmbeddingsResponse(error=None, vectors=vectors) + + await flow("response").send(response, properties={"id": id}) +``` + +#### Fase 2: Actualización del Procesador FastEmbed + +**Actual (Ineficiente):** +```python +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + vecs = self.embeddings.embed([text]) # Batch of 1 + return [v.tolist() for v in vecs] +``` + +**Actualizado:** +```python +async def on_embeddings(self, texts: list[str], model=None): + """Embed texts - processes all texts in single model call""" + if not texts: + return [] + + use_model = model or self.default_model + self._load_model(use_model) + + # FastEmbed handles the full batch efficiently + all_vecs = list(self.embeddings.embed(texts)) + + # Return list of vector sets, one per input text + return [[v.tolist()] for v in all_vecs] +``` + +#### Fase 3: Actualización del Servicio de Inserción de Gráficos + +**Actual (Serial):** +```python +async def on_message(self, msg, consumer, flow): + entities = [] + for entity in v.entities: + vectors = await flow("embeddings-request").embed(text=entity.context) + entities.append(EntityEmbeddings(...)) +``` + +**Actualizado (Lote):** +```python +async def on_message(self, msg, consumer, flow): + # Collect all contexts + contexts = [entity.context for entity in v.entities] + + # Single batch embedding call + all_vectors = await flow("embeddings-request").embed(texts=contexts) + + # Pair results with entities + entities = [ + EntityEmbeddings( + entity=entity.entity, + vectors=vectors[0], # First vector from the set + chunk_id=entity.chunk_id, + ) + for entity, vectors in zip(v.entities, all_vectors) + ] +``` + +#### Fase 4: Actualización del Servicio de Incrustación de Filas + +**Actual (Serial):** +```python +for text, (index_name, index_value) in texts_to_embed.items(): + vectors = await flow("embeddings-request").embed(text=text) + embeddings_list.append(RowIndexEmbedding(...)) +``` + +**Actualizado (Lote):** +```python +# Collect texts and metadata +texts = list(texts_to_embed.keys()) +metadata = list(texts_to_embed.values()) + +# Single batch embedding call +all_vectors = await flow("embeddings-request").embed(texts=texts) + +# Pair results +embeddings_list = [ + RowIndexEmbedding( + index_name=meta[0], + index_value=meta[1], + text=text, + vectors=vectors[0] # First vector from the set + ) + for text, meta, vectors in zip(texts, metadata, all_vectors) +] +``` + +#### Fase 5: Mejora de la Herramienta de Línea de Comandos (CLI) + +**CLI Actualizada:** +```python +def main(): + parser = argparse.ArgumentParser(...) + + parser.add_argument( + 'text', + nargs='*', # Zero or more texts + help='Text(s) to convert to embedding vectors', + ) + + parser.add_argument( + '-f', '--file', + help='File containing texts (one per line)', + ) + + parser.add_argument( + '--batch-size', + type=int, + default=32, + help='Batch size for processing (default: 32)', + ) +``` + +Uso: +```bash +# Single text (existing) +tg-invoke-embeddings "hello world" + +# Multiple texts +tg-invoke-embeddings "text one" "text two" "text three" + +# From file +tg-invoke-embeddings -f texts.txt --batch-size 64 +``` + +#### Fase 6: Mejora del SDK de Python + +**FlowInstance (cliente HTTP):** + +```python +class FlowInstance: + def embeddings(self, texts: list[str]) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + input = {"texts": texts} + return self.request("service/embeddings", input)["vectors"] +``` + +**SocketFlowInstance (cliente WebSocket):** + +```python +class SocketFlowInstance: + def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts via WebSocket. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + request = {"texts": texts} + response = self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) + return response["vectors"] +``` + +**Ejemplos de uso del SDK:** + +```python +# Single text +vectors = flow.embeddings(["hello world"]) +print(f"Dimensions: {len(vectors[0][0])}") + +# Batch embedding +texts = ["text one", "text two", "text three"] +all_vectors = flow.embeddings(texts) + +# Process results +for text, vecs in zip(texts, all_vectors): + print(f"{text}: {len(vecs[0])} dimensions") +``` + +## Consideraciones de seguridad + +**Límites de tamaño de la solicitud**: Aplicar un tamaño máximo de lote para evitar el agotamiento de recursos. +**Manejo de tiempos de espera**: Ajustar los tiempos de espera de manera adecuada para el tamaño del lote. +**Límites de memoria**: Monitorear el uso de memoria para lotes grandes. +**Validación de entrada**: Validar todos los textos en el lote antes de procesarlos. + +## Consideraciones de rendimiento + +### Mejoras esperadas + +**Rendimiento:** +Texto único: ~10-50 textos/segundo (dependiendo del modelo) +Lote (tamaño 32): ~200-500 textos/segundo (mejora de 5 a 10 veces) + +**Latencia por texto:** +Texto único: 50-200 ms por texto +Lote (tamaño 32): 5-20 ms por texto (promedio) + +**Mejoras específicas del servicio:** + +| Servicio | Actual | En lote | Mejora | +|---------|---------|---------|-------------| +| Incrustaciones de grafos (50 entidades) | 5-10 s | 0.5-1 s | 5-10 veces | +| Incrustaciones de filas (100 textos) | 10-20 s | 1-2 s | 5-10 veces | +| Ingestión de documentos (1000 fragmentos) | 100-200 s | 10-30 s | 5-10 veces | + +### Parámetros de configuración + +```python +# Recommended defaults +DEFAULT_BATCH_SIZE = 32 +MAX_BATCH_SIZE = 128 +BATCH_TIMEOUT_MULTIPLIER = 2.0 +``` + +## Estrategia de Pruebas + +### Pruebas Unitarias +Inserción de texto única (compatibilidad con versiones anteriores) +Manejo de lotes vacíos +Aplicación del tamaño máximo del lote +Manejo de errores para fallas parciales del lote + +### Pruebas de Integración +Inserción de lote de extremo a extremo a través de Pulsar +Procesamiento por lotes del servicio de inserción de gráficos +Procesamiento por lotes del servicio de inserción de filas +Punto final de lote de la puerta de enlace de la API + +### Pruebas de Rendimiento +Comparación de rendimiento de inserción única frente a inserción por lotes +Uso de memoria con varios tamaños de lote +Análisis de la distribución de la latencia + +## Plan de Migración + +Esta es una versión que introduce cambios importantes. Todas las fases se implementan juntas. + +### Fase 1: Cambios en el Esquema +Reemplazar `text: str` con `texts: list[str]` en EmbeddingsRequest +Cambiar el tipo de `vectors` a `list[list[list[float]]]` en EmbeddingsResponse + +### Fase 2: Actualizaciones del Procesador +Actualizar la firma de `on_embeddings` en los procesadores FastEmbed y Ollama +Procesar el lote completo en una única llamada al modelo + +### Fase 3: Actualizaciones del Cliente +Actualizar `EmbeddingsClient.embed()` para que acepte `texts: list[str]` + +### Fase 4: Actualizaciones del Llamador +Actualizar graph_embeddings para procesar contextos de entidades por lotes +Actualizar row_embeddings para procesar textos de índice por lotes +Actualizar document_embeddings para usar el nuevo esquema +Actualizar la herramienta de línea de comandos + +### Fase 5: Puerta de Enlace de la API +Actualizar el punto final de inserción para el nuevo esquema + +### Fase 6: SDK de Python +Actualizar la firma de `FlowInstance.embeddings()` +Actualizar la firma de `SocketFlowInstance.embeddings()` + +## Preguntas Abiertas + +**Inserción de Lotes Grandes en Streaming**: ¿Debemos admitir la transmisión de resultados para lotes muy grandes (>100 textos)? +**Límites Específicos del Proveedor**: ¿Cómo debemos manejar los proveedores con tamaños máximos de lote diferentes? +**Manejo de Fallas Parciales**: Si un texto en un lote falla, ¿deberíamos fallar todo el lote o devolver resultados parciales? +**Inserción por Lotes de Documentos**: ¿Debemos realizar la inserción por lotes en varios mensajes de Chunk o mantener el procesamiento por mensaje? + +## Referencias + +[Documentación de FastEmbed](https://github.com/qdrant/fastembed) +[API de Inserción de Ollama](https://github.com/ollama/ollama) +[Implementación del Servicio de Inserción](trustgraph-base/trustgraph/base/embeddings_service.py) +[Optimización del Rendimiento de GraphRAG](graphrag-performance-optimization.md) diff --git a/docs/tech-specs/embeddings-batch-processing.he.md b/docs/tech-specs/embeddings-batch-processing.he.md new file mode 100644 index 00000000..21ad2e6a --- /dev/null +++ b/docs/tech-specs/embeddings-batch-processing.he.md @@ -0,0 +1,667 @@ +# מפרט טכני לעיבוד אצווה של הטמעות (Embeddings) + +## סקירה כללית + +מפרט זה מתאר אופטימיזציות עבור שירות ההטמעות כדי לתמוך בעיבוד אצווה של מספר טקסטים בבקשה אחת. היישום הנוכחי מעבד טקסט אחד בכל פעם, ואינו מנצל את היתרונות המשמעותיים בביצועים שמודלי הטמעה מספקים בעת עיבוד אצוות. + +1. **חוסר יעילות בעיבוד טקסט בודד**: היישום הנוכחי עוטף טקסטים בודדים ברשימה, ובכך אינו מנצל את יכולות האצווה של FastEmbed. +2. **תקורה של בקשה לטקסט**: כל טקסט דורש הודעת Pulsar נפרדת הלוך ושוב. +3. **חוסר יעילות בהסקת מודל**: למודלי הטמעה יש תקורה קבועה לכל אצווה; אצוות קטנות מבזבזות משאבי GPU/CPU. +4. **עיבוד סדרתי בלקוחות**: שירותים מרכזיים עוברים בלולאה על פריטים וקוראים להטמעות אחד בכל פעם. + +## מטרות + +**תמיכה בממשק API לאצוות**: לאפשר עיבוד של מספר טקסטים בבקשה אחת. +**תאימות לאחור**: לשמור על תמיכה בבקשות לטקסט בודד. +**שיפור משמעותי בביצועים**: לכוון לשיפור של 5-10x בביצועים עבור פעולות אצווה. +**הפחתת השהייה לטקסט**: להוריד את ההשהייה הממוצעת בעת הטמעת מספר טקסטים. +**יעילות בשימוש בזיכרון**: לעבד אצוות מבלי לצרוך כמות מוגזמת של זיכרון. +**אי-תלות בספק**: לתמוך באצוות בין FastEmbed, Ollama וספקים אחרים. +**מעבר של לקוחות**: לעדכן את כל לקוחות ההטמעות כדי להשתמש בממשק ה-API לאצוות כאשר זה מועיל. + +## רקע + +### יישום נוכחי - שירות הטמעות + +היישום של ההטמעות ב-`trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` מציג חוסר יעילות משמעותי בביצועים: + +```python +# fastembed/processor.py line 56 +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + + vecs = self.embeddings.embed([text]) # Single text wrapped in list + + return [v.tolist() for v in vecs] +``` + +**בעיות:** + +1. **גודל אצווה 1**: השיטה `embed()` של FastEmbed מותאמת לעיבוד באצווה, אך אנו תמיד משתמשים בה עם `[text]` - אצווה בגודל 1. + +2. **תקורה לכל בקשה:** כל בקשת הטמעה כרוכה ב: + סריאליזציה/דה-סריאליזציה של הודעת Pulsar + השהייה של תקשורת רשת + תקורה של אתחול הסקה של המודל + תקורה של תזמון אסינכרוני של Python + +3. **מגבלת סכימה:** הסכימה `EmbeddingsRequest` תומכת רק בטקסט אחד: + ```python + @dataclass + class EmbeddingsRequest: + text: str = "" # Single text only + ``` + +### לקוחות נוכחיים - עיבוד סדרתי + +#### 1. שער API + +**קובץ:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +השער מקבל בקשות להטמעה של טקסט בודד באמצעות HTTP/WebSocket ומעביר אותן לשירות ההטמעה. כרגע אין נקודת קצה לעיבוד אצווה. + +```python +class EmbeddingsRequestor(ServiceRequestor): + # Handles single EmbeddingsRequest -> EmbeddingsResponse + request_schema=EmbeddingsRequest, # Single text only + response_schema=EmbeddingsResponse, +``` + +**השפעה:** לקוחות חיצוניים (אפליקציות אינטרנט, סקריפטים) חייבים לבצע N בקשות HTTP כדי להטמיע N טקסטים. + +#### 2. שירות הטמעת מסמכים + +**קובץ:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +מעבד פיסות של מסמכים אחת בכל פעם: + +```python +async def on_message(self, msg, consumer, flow): + v = msg.value() + + # Single chunk per request + resp = await flow("embeddings-request").request( + EmbeddingsRequest(text=v.chunk) + ) + vectors = resp.vectors +``` + +**השפעה:** כל חלק במסמך דורש קריאת הטמעה נפרדת. מסמך עם 100 חלקים = 100 בקשות הטמעה. + +#### 3. שירות הטמעת גרפים + +**קובץ:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + +עובר בלולאה על ישויות ומטמיע כל אחת בנפרד: + +```python +async def on_message(self, msg, consumer, flow): + for entity in v.entities: + # Serial embedding - one entity at a time + vectors = await flow("embeddings-request").embed( + text=entity.context + ) + entities.append(EntityEmbeddings( + entity=entity.entity, + vectors=vectors, + chunk_id=entity.chunk_id, + )) +``` + +**השפעה:** הודעה עם 50 ישויות = 50 בקשות הטמעה סדרתיות. זהו צוואר בקבוק משמעותי במהלך בניית גרף ידע. + +#### 4. שירות הטמעת שורות + +**קובץ:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + +חוזר על טקסטים ייחודיים ומטמיע כל אחד מהם באופן סדרתי: + +```python +async def on_message(self, msg, consumer, flow): + for text, (index_name, index_value) in texts_to_embed.items(): + # Serial embedding - one text at a time + vectors = await flow("embeddings-request").embed(text=text) + + embeddings_list.append(RowIndexEmbedding( + index_name=index_name, + index_value=index_value, + text=text, + vectors=vectors + )) +``` + +**השפעה:** עיבוד טבלה עם 100 ערכים ייחודיים עם אינדקס = 100 בקשות הטמעה סדרתיות. + +#### 5. EmbeddingsClient (לקוח בסיסי) + +**קובץ:** `trustgraph-base/trustgraph/base/embeddings_client.py` + +הלקוח המשמש את כל מעבדי הזרימה תומך רק בהטמעה של טקסט בודד: + +```python +class EmbeddingsClient(RequestResponse): + async def embed(self, text, timeout=30): + resp = await self.request( + EmbeddingsRequest(text=text), # Single text + timeout=timeout + ) + return resp.vectors +``` + +**השפעה:** כל המשתמשים בלקוח זה מוגבלים לפעולות טקסט יחידות. + +#### 6. כלי שורת הפקודה + +**קובץ:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +כלי שורת הפקודה מקבל ארגומנט טקסט יחיד: + +```python +def query(url, flow_id, text, token=None): + result = flow.embeddings(text=text) # Single text + vectors = result.get("vectors", []) +``` + +**השפעה:** משתמשים אינם יכולים לבצע הטמעה אצווה משורת הפקודה. עיבוד קובץ של טקסטים דורש N הפעלות. + +#### 7. ערכת פיתוח תוכנה (SDK) עבור Python + +ערכת הפיתוח תוכנה עבור Python מספקת שתי מחלקות לקוח לצורך אינטראקציה עם שירותי TrustGraph. שתיהן תומכות רק בהטמעה של טקסט בודד. + +**קובץ:** `trustgraph-base/trustgraph/api/flow.py` + +```python +class FlowInstance: + def embeddings(self, text): + """Get embeddings for a single text""" + input = {"text": text} + return self.request("service/embeddings", input)["vectors"] +``` + +**קובץ:** `trustgraph-base/trustgraph/api/socket_client.py` + +```python +class SocketFlowInstance: + def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]: + """Get embeddings for a single text via WebSocket""" + request = {"text": text} + return self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) +``` + +**השפעה:** מפתחי Python המשתמשים ב-SDK חייבים לעבור על הטקסטים ולבצע N קריאות API נפרדות. אין תמיכה בהטמעה באצווה עבור משתמשי ה-SDK. + +### השפעה על הביצועים + +עבור הכנסת מסמכים טיפוסית (1000 מקטעי טקסט): +**נוכחי**: 1000 בקשות נפרדות, 1000 קריאות למודל +**באצווה (batch_size=32)**: 32 בקשות, 32 קריאות למודל (הפחתה של 96.8%) + +עבור הטמעת גרפים (הודעה עם 50 ישויות): +**נוכחי**: 50 קריאות await סדרתיות, ~5-10 שניות +**באצווה**: 1-2 קריאות באצווה, ~0.5-1 שניה (שיפור של 5-10x) + +ספריות כמו FastEmbed ודומות משיגות התרחבות כמעט ליניארית של התפוקה עם גודל האצווה עד לגבולות החומרה (בדרך כלל 32-128 טקסטים לאצווה). + +## עיצוב טכני + +### ארכיטקטורה + +אופטימיזציה של עיבוד אצווה להטמעות דורשת שינויים ברכיבים הבאים: + +#### 1. **שיפור סכימה** + הרחבת `EmbeddingsRequest` לתמיכה במספר טקסטים + הרחבת `EmbeddingsResponse` להחזרת מספר סטים של וקטורים + שמירה על תאימות לאחור לבקשות טקסט בודדות + + מודול: `trustgraph-base/trustgraph/schema/services/llm.py` + +#### 2. **שיפור שירות בסיסי** + עדכון `EmbeddingsService` לטיפול בבקשות באצווה + הוספת תצורת גודל אצווה + יישום טיפול בבקשות מודע לאצווה + + מודול: `trustgraph-base/trustgraph/base/embeddings_service.py` + +#### 3. **עדכוני מעבד ספק** + עדכון מעבד FastEmbed להעברת אצווה שלמה ל-`embed()` + עדכון מעבד Ollama לטיפול באצווה (אם נתמך) + הוספת עיבוד רציף כברירת מחדל עבור ספקים שאינם תומכים באצווה + + מודולים: + `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` + `trustgraph-flow/trustgraph/embeddings/ollama/processor.py` + +#### 4. **שיפור לקוח** + הוספת שיטה להטמעה באצווה ל-`EmbeddingsClient` + תמיכה גם ב-API של טקסט בודד וגם ב-API של אצווה + הוספת אצווה אוטומטית עבור קלט גדול + + מודול: `trustgraph-base/trustgraph/base/embeddings_client.py` + +#### 5. **עדכוני קוראים - מעבדי זרימה** + עדכון `graph_embeddings` לאצווה של הקשרים של ישויות + עדכון `row_embeddings` לאצווה של טקסטים לאינדקס + עדכון `document_embeddings` אם אצווה של הודעות אפשרית + + מודולים: + `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +#### 6. **שיפור שער API** + הוספת נקודת קצה להטמעה באצווה + תמיכה במערך של טקסטים בגוף הבקשה + + מודול: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +#### 7. **שיפור כלי שורת הפקודה** + הוספת תמיכה במספר טקסטים או קלט של קובץ + הוספת פרמטר גודל אצווה + + מודול: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +#### 8. **שיפור SDK של Python** + הוספת שיטה `embeddings_batch()` ל-`FlowInstance` + הוספת שיטה `embeddings_batch()` ל-`SocketFlowInstance` + תמיכה גם ב-API של טקסט בודד וגם ב-API של אצווה עבור משתמשי SDK + + מודולים: + `trustgraph-base/trustgraph/api/flow.py` + `trustgraph-base/trustgraph/api/socket_client.py` + +### מודלים של נתונים + +#### EmbeddingsRequest + +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +שימוש: +טקסט בודד: `EmbeddingsRequest(texts=["hello world"])` +אצווה: `EmbeddingsRequest(texts=["text1", "text2", "text3"])` + +#### EmbeddingsResponse + +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +מבנה התגובה: +`vectors[i]` מכיל את קבוצת הווקטורים עבור `texts[i]` +כל קבוצת וקטורים היא `list[list[float]]` (מודלים עשויים להחזיר מספר וקטורים עבור כל טקסט) +דוגמה: 3 טקסטים → `vectors` מכיל 3 רשומות, כאשר כל רשומה מכילה את הטבעות של הטקסט המתאים + +### ממשקי API + +#### EmbeddingsClient + +```python +class EmbeddingsClient(RequestResponse): + async def embed( + self, + texts: list[str], + timeout: float = 300, + ) -> list[list[list[float]]]: + """ + Embed one or more texts in a single request. + + Args: + texts: List of texts to embed + timeout: Timeout for the operation + + Returns: + List of vector sets, one per input text + """ + resp = await self.request( + EmbeddingsRequest(texts=texts), + timeout=timeout + ) + if resp.error: + raise RuntimeError(resp.error.message) + return resp.vectors +``` + +#### נקודת קצה של הטמעות (Embeddings) עבור שער API + +נקודת קצה מעודכנת התומכת בהטמעה בודדת או באצווה: + +``` +POST /api/v1/embeddings +Content-Type: application/json + +{ + "texts": ["text1", "text2", "text3"], + "flow_id": "default" +} + +Response: +{ + "vectors": [ + [[0.1, 0.2, ...]], + [[0.3, 0.4, ...]], + [[0.5, 0.6, ...]] + ] +} +``` + +### פרטי יישום + +#### שלב 1: שינויי סכימה + +**EmbeddingsRequest:** +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +**תגובת הטבעה (EmbeddingsResponse):** +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +**עדכון של EmbeddingsService.on_request:** +```python +async def on_request(self, msg, consumer, flow): + request = msg.value() + id = msg.properties()["id"] + model = flow("model") + + vectors = await self.on_embeddings(request.texts, model=model) + response = EmbeddingsResponse(error=None, vectors=vectors) + + await flow("response").send(response, properties={"id": id}) +``` + +#### שלב 2: עדכון מעבד FastEmbed + +**נוכחי (לא יעיל):** +```python +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + vecs = self.embeddings.embed([text]) # Batch of 1 + return [v.tolist() for v in vecs] +``` + +**עדכון:** +```python +async def on_embeddings(self, texts: list[str], model=None): + """Embed texts - processes all texts in single model call""" + if not texts: + return [] + + use_model = model or self.default_model + self._load_model(use_model) + + # FastEmbed handles the full batch efficiently + all_vecs = list(self.embeddings.embed(texts)) + + # Return list of vector sets, one per input text + return [[v.tolist()] for v in all_vecs] +``` + +#### שלב 3: עדכון שירות הטמעת גרפים + +**נוכחי (סדרתי):** +```python +async def on_message(self, msg, consumer, flow): + entities = [] + for entity in v.entities: + vectors = await flow("embeddings-request").embed(text=entity.context) + entities.append(EntityEmbeddings(...)) +``` + +**עדכון (אצווה):** +```python +async def on_message(self, msg, consumer, flow): + # Collect all contexts + contexts = [entity.context for entity in v.entities] + + # Single batch embedding call + all_vectors = await flow("embeddings-request").embed(texts=contexts) + + # Pair results with entities + entities = [ + EntityEmbeddings( + entity=entity.entity, + vectors=vectors[0], # First vector from the set + chunk_id=entity.chunk_id, + ) + for entity, vectors in zip(v.entities, all_vectors) + ] +``` + +#### שלב 4: עדכון שירות הטמעת שורות + +**נוכחי (סדרתי):** +```python +for text, (index_name, index_value) in texts_to_embed.items(): + vectors = await flow("embeddings-request").embed(text=text) + embeddings_list.append(RowIndexEmbedding(...)) +``` + +**עדכון (אצווה):** +```python +# Collect texts and metadata +texts = list(texts_to_embed.keys()) +metadata = list(texts_to_embed.values()) + +# Single batch embedding call +all_vectors = await flow("embeddings-request").embed(texts=texts) + +# Pair results +embeddings_list = [ + RowIndexEmbedding( + index_name=meta[0], + index_value=meta[1], + text=text, + vectors=vectors[0] # First vector from the set + ) + for text, meta, vectors in zip(texts, metadata, all_vectors) +] +``` + +#### שלב 5: שיפור כלי שורת הפקודה + +**שורת פקודה מעודכנת:** +```python +def main(): + parser = argparse.ArgumentParser(...) + + parser.add_argument( + 'text', + nargs='*', # Zero or more texts + help='Text(s) to convert to embedding vectors', + ) + + parser.add_argument( + '-f', '--file', + help='File containing texts (one per line)', + ) + + parser.add_argument( + '--batch-size', + type=int, + default=32, + help='Batch size for processing (default: 32)', + ) +``` + +שימוש: +```bash +# Single text (existing) +tg-invoke-embeddings "hello world" + +# Multiple texts +tg-invoke-embeddings "text one" "text two" "text three" + +# From file +tg-invoke-embeddings -f texts.txt --batch-size 64 +``` + +#### שלב 6: שיפור ערכת הפיתוח של Python + +**FlowInstance (לקוח HTTP):** + +```python +class FlowInstance: + def embeddings(self, texts: list[str]) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + input = {"texts": texts} + return self.request("service/embeddings", input)["vectors"] +``` + +**SocketFlowInstance (לקוח WebSocket):** + +```python +class SocketFlowInstance: + def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts via WebSocket. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + request = {"texts": texts} + response = self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) + return response["vectors"] +``` + +**דוגמאות לשימוש ב-SDK:** + +```python +# Single text +vectors = flow.embeddings(["hello world"]) +print(f"Dimensions: {len(vectors[0][0])}") + +# Batch embedding +texts = ["text one", "text two", "text three"] +all_vectors = flow.embeddings(texts) + +# Process results +for text, vecs in zip(texts, all_vectors): + print(f"{text}: {len(vecs[0])} dimensions") +``` + +## שיקולי אבטחה + +**מגבלות גודל בקשה**: אכוף גודל מקסימלי לאצווה כדי למנוע מיצוי משאבים +**טיפול בזמני המתנה**: התאם את זמני ההמתנה בהתאם לגודל האצווה +**מגבלות זיכרון**: עקוב אחר השימוש בזיכרון עבור אצוות גדולות +**אימות קלט**: אשר את כל הטקסטים באצווה לפני העיבוד + +## שיקולי ביצועים + +### שיפורים צפויים + +**קצב העברה (Throughput):** +טקסט בודד: ~10-50 טקסטים/שנייה (תלוי במודל) +אצווה (גודל 32): ~200-500 טקסטים/שנייה (שיפור של 5-10x) + +**זמן תגובה לטקסט:** +טקסט בודד: 50-200ms לטקסט +אצווה (גודל 32): 5-20ms לטקסט (ממוצע) + +**שיפורים ספציפיים לשירות:** + +| שירות | נוכחי | באצווה | שיפור | +|---------|---------|---------|-------------| +| הטמעת גרפים (50 ישויות) | 5-10 שניות | 0.5-1 שניות | 5-10x | +| הטמעת שורות (100 טקסטים) | 10-20 שניות | 1-2 שניות | 5-10x | +| קליטת מסמכים (1000 מקטעים) | 100-200 שניות | 10-30 שניות | 5-10x | + +### פרמטרי תצורה + +```python +# Recommended defaults +DEFAULT_BATCH_SIZE = 32 +MAX_BATCH_SIZE = 128 +BATCH_TIMEOUT_MULTIPLIER = 2.0 +``` + +## אסטרטגיית בדיקות + +### בדיקות יחידה +הטמעה של טקסט בודד (תאימות לאחור) +טיפול באצווה ריקה +אכיפת גודל אצווה מקסימלי +טיפול בשגיאות עבור כשלים חלקיים באצווה + +### בדיקות אינטגרציה +הטמעת אצווה מקצה לקצה דרך Pulsar +עיבוד אצווה בשירות הטמעת גרפים +עיבוד אצווה בשירות הטמעת שורות +נקודת קצה של אצווה בשער ה-API + +### בדיקות ביצועים +השוואת תפוקה של הטמעה בודדת לעומת אצווה +שימוש בזיכרון בגדלי אצווה שונים +ניתוח התפלגות השהייה + +## תוכנית מעבר + +זו גרסה הכוללת שינויים משמעותיים. כל השלבים מיושמים יחד. + +### שלב 1: שינויי סכימה +החלפת `text: str` ב-`texts: list[str]` ב-EmbeddingsRequest +שינוי סוג של `vectors` ל-`list[list[list[float]]]` ב-EmbeddingsResponse + +### שלב 2: עדכוני מעבד +עדכון חתימה של `on_embeddings` במעבדים FastEmbed ו-Ollama +עיבוד אצווה שלמה בפעילת מודל אחת + +### שלב 3: עדכוני לקוח +עדכון `EmbeddingsClient.embed()` כדי לקבל `texts: list[str]` + +### שלב 4: עדכוני משתמשים +עדכון graph_embeddings להטמעת הקשרים של ישויות באצווה +עדכון row_embeddings לעיבוד אצווה של טקסטים באינדקס +עדכון document_embeddings לשימוש בסכימה החדשה +עדכון כלי שורת הפקודה + +### שלב 5: שער API +עדכון נקודת קצה של הטמעה עבור סכימה חדשה + +### שלב 6: SDK של Python +עדכון חתימה של `FlowInstance.embeddings()` +עדכון חתימה של `SocketFlowInstance.embeddings()` + +## שאלות פתוחות + +**הטמעת אצוות גדולות**: האם עלינו לתמוך בהעברת תוצאות עבור אצוות גדולות מאוד (>100 טקסטים)? +**מגבלות ספציפיות לספק**: כיצד עלינו להתמודד עם ספקים עם גודל אצווה מקסימלי שונה? +**טיפול בכשלים חלקיים**: אם טקסט אחד באצווה נכשל, האם עלינו לגרום לכשל באצווה כולה או להחזיר תוצאות חלקיות? +**הטמעת מסמכים באצווה**: האם עלינו לבצע אצווה בין הודעות Chunk מרובות או לשמור על עיבוד פר-הודעה? + +## הפניות + +[תיעוד FastEmbed](https://github.com/qdrant/fastembed) +[ממשק API של הטמעות Ollama](https://github.com/ollama/ollama) +[יישום של EmbeddingsService](trustgraph-base/trustgraph/base/embeddings_service.py) +[אופטימיזציה של ביצועים של GraphRAG](graphrag-performance-optimization.md) diff --git a/docs/tech-specs/embeddings-batch-processing.hi.md b/docs/tech-specs/embeddings-batch-processing.hi.md new file mode 100644 index 00000000..2b519f64 --- /dev/null +++ b/docs/tech-specs/embeddings-batch-processing.hi.md @@ -0,0 +1,667 @@ +# एम्बेडिंग बैच प्रोसेसिंग तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश एम्बेडिंग सेवा के लिए अनुकूलन का वर्णन करता है ताकि एक ही अनुरोध में कई ग्रंथों को बैच में संसाधित किया जा सके। वर्तमान कार्यान्वयन एक समय में एक पाठ को संसाधित करता है, जिससे एम्बेडिंग मॉडल द्वारा प्रदान किए जाने वाले महत्वपूर्ण प्रदर्शन लाभों का उपयोग नहीं हो पाता है जब बैचों में प्रसंस्करण किया जाता है। + +1. **सिंगल-टेक्स्ट प्रोसेसिंग की अक्षमता**: वर्तमान कार्यान्वयन एकल ग्रंथों को एक सूची में लपेटता है, जिससे FastEmbed की बैच क्षमताओं का पूरी तरह से उपयोग नहीं हो पाता है। +2. **प्रति-टेक्स्ट अनुरोध ओवरहेड**: प्रत्येक पाठ के लिए एक अलग पल्सर संदेश राउंड-ट्रिप की आवश्यकता होती है। +3. **मॉडल अनुमान की अक्षमता**: एम्बेडिंग मॉडल में एक निश्चित प्रति-बैच ओवरहेड होता है; छोटे बैच GPU/CPU संसाधनों को बर्बाद करते हैं। +4. **कॉलरों में सीरियल प्रोसेसिंग**: प्रमुख सेवाएं आइटम्स पर लूप करती हैं और एक-एक करके एम्बेडिंग को कॉल करती हैं। + +## लक्ष्य + +**बैच एपीआई समर्थन**: एक ही अनुरोध में कई ग्रंथों को संसाधित करने की क्षमता सक्षम करें। +**पिछड़ा संगतता**: एकल-पाठ अनुरोधों के लिए समर्थन बनाए रखें। +**महत्वपूर्ण थ्रूपुट सुधार**: बल्क ऑपरेशनों के लिए 5-10 गुना थ्रूपुट सुधार का लक्ष्य रखें। +**प्रति-पाठ कम विलंबता**: कई ग्रंथों को एम्बेड करते समय औसत विलंबता को कम करें। +**मेमोरी दक्षता**: अत्यधिक मेमोरी खपत के बिना बैचों को संसाधित करें। +**प्रदाता-अज्ञेय**: FastEmbed, Ollama और अन्य प्रदाताओं में बैचिंग का समर्थन करें। +**कॉलर माइग्रेशन**: सभी एम्बेडिंग कॉलरों को अपडेट करें ताकि वे जहां फायदेमंद हो वहां बैच एपीआई का उपयोग करें। + +## पृष्ठभूमि + +### वर्तमान कार्यान्वयन - एम्बेडिंग सेवा + +`trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` में एम्बेडिंग कार्यान्वयन में एक महत्वपूर्ण प्रदर्शन अक्षमता है: + +```python +# fastembed/processor.py line 56 +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + + vecs = self.embeddings.embed([text]) # Single text wrapped in list + + return [v.tolist() for v in vecs] +``` + +**समस्याएँ:** + +1. **बैच का आकार 1**: FastEmbed का `embed()` तरीका बैच प्रोसेसिंग के लिए अनुकूलित है, लेकिन हम हमेशा इसे `[text]` के साथ कॉल करते हैं - जो कि आकार 1 का एक बैच है। + +2. **प्रति-अनुरोध ओवरहेड**: प्रत्येक एम्बेडिंग अनुरोध में शामिल हैं: + पल्सर संदेश का क्रमबद्धता/विघटन + नेटवर्क राउंड-ट्रिप विलंबता + मॉडल अनुमान स्टार्टअप ओवरहेड + पायथन एसिंक्रोनस शेड्यूलिंग ओवरहेड + +3. **स्कीमा सीमा**: `EmbeddingsRequest` स्कीमा केवल एक टेक्स्ट का समर्थन करता है: + ```python + @dataclass + class EmbeddingsRequest: + text: str = "" # Single text only + ``` + +### वर्तमान कॉलर - सीरियल प्रोसेसिंग + +#### 1. एपीआई गेटवे + +**फ़ाइल:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +गेटवे HTTP/WebSocket के माध्यम से सिंगल-टेक्स्ट एम्बेडिंग अनुरोध स्वीकार करता है और उन्हें एम्बेडिंग सेवा को भेजता है। वर्तमान में कोई बैच एंडपॉइंट मौजूद नहीं है। + +```python +class EmbeddingsRequestor(ServiceRequestor): + # Handles single EmbeddingsRequest -> EmbeddingsResponse + request_schema=EmbeddingsRequest, # Single text only + response_schema=EmbeddingsResponse, +``` + +**प्रभाव:** बाहरी क्लाइंट (वेब ऐप्स, स्क्रिप्ट) को N टेक्स्ट एम्बेड करने के लिए N HTTP अनुरोध करने होंगे। + +#### 2. दस्तावेज़ एम्बेडिंग सेवा + +**फ़ाइल:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +दस्तावेज़ के टुकड़ों को एक-एक करके संसाधित करता है: + +```python +async def on_message(self, msg, consumer, flow): + v = msg.value() + + # Single chunk per request + resp = await flow("embeddings-request").request( + EmbeddingsRequest(text=v.chunk) + ) + vectors = resp.vectors +``` + +**प्रभाव:** प्रत्येक दस्तावेज़ खंड के लिए एक अलग एम्बेडिंग कॉल की आवश्यकता होती है। 100 खंडों वाला एक दस्तावेज़ = 100 एम्बेडिंग अनुरोध। + +#### 3. ग्राफ एम्बेडिंग सेवा + +**फ़ाइल:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + +यह एंटिटीज पर लूप करता है और प्रत्येक को क्रमिक रूप से एम्बेड करता है: + +```python +async def on_message(self, msg, consumer, flow): + for entity in v.entities: + # Serial embedding - one entity at a time + vectors = await flow("embeddings-request").embed( + text=entity.context + ) + entities.append(EntityEmbeddings( + entity=entity.entity, + vectors=vectors, + chunk_id=entity.chunk_id, + )) +``` + +**प्रभाव:** 50 एंटिटीज वाला एक संदेश = 50 सीरियल एम्बेडिंग अनुरोध। यह ज्ञान ग्राफ निर्माण के दौरान एक बड़ी बाधा है। + +#### 4. रो एम्बेडिंग सेवा + +**फ़ाइल:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + +यह अद्वितीय टेक्स्ट पर लूप करता है और प्रत्येक को क्रमिक रूप से एम्बेड करता है: + +```python +async def on_message(self, msg, consumer, flow): + for text, (index_name, index_value) in texts_to_embed.items(): + # Serial embedding - one text at a time + vectors = await flow("embeddings-request").embed(text=text) + + embeddings_list.append(RowIndexEmbedding( + index_name=index_name, + index_value=index_value, + text=text, + vectors=vectors + )) +``` + +**प्रभाव:** 100 अद्वितीय अनुक्रमित मानों वाली तालिका को संसाधित करने से 100 सीरियल एम्बेडिंग अनुरोध उत्पन्न होते हैं। + +#### 5. एम्बेडिंग्सक्लाइंट (बेस क्लाइंट) + +**फ़ाइल:** `trustgraph-base/trustgraph/base/embeddings_client.py` + +सभी फ्लो प्रोसेसर द्वारा उपयोग किए जाने वाले क्लाइंट केवल सिंगल-टेक्स्ट एम्बेडिंग का समर्थन करते हैं: + +```python +class EmbeddingsClient(RequestResponse): + async def embed(self, text, timeout=30): + resp = await self.request( + EmbeddingsRequest(text=text), # Single text + timeout=timeout + ) + return resp.vectors +``` + +**प्रभाव:** इस क्लाइंट का उपयोग करने वाले सभी एप्लिकेशन केवल एकल-पाठ संचालन तक सीमित हैं। + +#### 6. कमांड-लाइन उपकरण + +**फ़ाइल:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +कमांड-लाइन उपकरण एक एकल पाठ तर्क स्वीकार करता है: + +```python +def query(url, flow_id, text, token=None): + result = flow.embeddings(text=text) # Single text + vectors = result.get("vectors", []) +``` + +**प्रभाव:** उपयोगकर्ता कमांड लाइन से बैच एम्बेडिंग नहीं कर सकते। टेक्स्ट फ़ाइल को संसाधित करने के लिए N बार कॉल की आवश्यकता होती है। + +#### 7. पायथन SDK + +पायथन SDK ट्रस्टग्राफ सेवाओं के साथ इंटरैक्ट करने के लिए दो क्लाइंट क्लास प्रदान करता है। दोनों केवल सिंगल-टेक्स्ट एम्बेडिंग का समर्थन करते हैं। + +**फ़ाइल:** `trustgraph-base/trustgraph/api/flow.py` + +```python +class FlowInstance: + def embeddings(self, text): + """Get embeddings for a single text""" + input = {"text": text} + return self.request("service/embeddings", input)["vectors"] +``` + +**फ़ाइल:** `trustgraph-base/trustgraph/api/socket_client.py` + +```python +class SocketFlowInstance: + def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]: + """Get embeddings for a single text via WebSocket""" + request = {"text": text} + return self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) +``` + +**प्रभाव:** एसडीके का उपयोग करने वाले पायथन डेवलपर्स को टेक्स्ट पर लूप करना होगा और एन अलग एपीआई कॉल करने होंगे। एसडीके उपयोगकर्ताओं के लिए कोई बैच एम्बेडिंग समर्थन मौजूद नहीं है। + +### प्रदर्शन प्रभाव + +सामान्य दस्तावेज़ इनपुट (1000 टेक्स्ट खंड) के लिए: +**वर्तमान:** 1000 अलग-अलग अनुरोध, 1000 मॉडल अनुमान कॉल +**बैच (batch_size=32):** 32 अनुरोध, 32 मॉडल अनुमान कॉल (96.8% कमी) + +ग्राफ एम्बेडिंग (50 संस्थाओं वाला संदेश) के लिए: +**वर्तमान:** 50 सीरियल अवित कॉल, ~5-10 सेकंड +**बैच:** 1-2 बैच कॉल, ~0.5-1 सेकंड (5-10 गुना सुधार) + +FastEmbed और समान लाइब्रेरी हार्डवेयर सीमाओं तक बैच आकार के साथ लगभग रैखिक थ्रूपुट स्केलिंग प्राप्त करती हैं (आमतौर पर प्रति बैच 32-128 टेक्स्ट)। + +## तकनीकी डिज़ाइन + +### आर्किटेक्चर + +एम्बेडिंग बैच प्रोसेसिंग अनुकूलन के लिए निम्नलिखित घटकों में परिवर्तन की आवश्यकता है: + +#### 1. **स्कीमा संवर्धन** + `EmbeddingsRequest` को कई टेक्स्ट का समर्थन करने के लिए विस्तारित करें + `EmbeddingsResponse` को कई वेक्टर सेट वापस करने के लिए विस्तारित करें + एकल-टेक्स्ट अनुरोधों के साथ पिछड़े अनुकूलता बनाए रखें + + मॉड्यूल: `trustgraph-base/trustgraph/schema/services/llm.py` + +#### 2. **बेस सर्विस संवर्धन** + `EmbeddingsService` को बैच अनुरोधों को संभालने के लिए अपडेट करें + बैच आकार कॉन्फ़िगरेशन जोड़ें + बैच-जागरूक अनुरोध हैंडलिंग लागू करें + + मॉड्यूल: `trustgraph-base/trustgraph/base/embeddings_service.py` + +#### 3. **प्रदाता प्रोसेसर अपडेट** + FastEmbed प्रोसेसर को अपडेट करें ताकि `embed()` को पूरा बैच पास किया जा सके + यदि समर्थित है, तो बैचों को संभालने के लिए Ollama प्रोसेसर को अपडेट करें + बैच समर्थन के बिना प्रदाताओं के लिए एक वैकल्पिक अनुक्रमिक प्रसंस्करण जोड़ें + + मॉड्यूल: + `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` + `trustgraph-flow/trustgraph/embeddings/ollama/processor.py` + +#### 4. **क्लाइंट में सुधार** + `EmbeddingsClient` में बैच एम्बेडिंग विधि जोड़ें + सिंगल और बैच एपीआई दोनों का समर्थन करें + बड़े इनपुट के लिए स्वचालित बैचिंग जोड़ें + + मॉड्यूल: `trustgraph-base/trustgraph/base/embeddings_client.py` + +#### 5. **कॉल करने वाले अपडेट - फ्लो प्रोसेसर** + `graph_embeddings` को बैच एंटिटी कॉन्टेक्स्ट के लिए अपडेट करें + `row_embeddings` को बैच इंडेक्स टेक्स्ट के लिए अपडेट करें + यदि संदेश बैचिंग संभव है, तो `document_embeddings` को अपडेट करें + + मॉड्यूल: + `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +#### 6. **एपीआई गेटवे में सुधार** + बैच एम्बेडिंग एंडपॉइंट जोड़ें + अनुरोध बॉडी में टेक्स्ट की सरणी का समर्थन करें + + मॉड्यूल: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +#### 7. **सीएलआई टूल में सुधार** + कई टेक्स्ट या फ़ाइल इनपुट के लिए समर्थन जोड़ें + बैच आकार पैरामीटर जोड़ें + + मॉड्यूल: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +#### 8. **पायथन एसडीके में सुधार** + `FlowInstance` में `embeddings_batch()` विधि जोड़ें + `SocketFlowInstance` में `embeddings_batch()` विधि जोड़ें + एसडीके उपयोगकर्ताओं के लिए सिंगल और बैच एपीआई दोनों का समर्थन करें + + मॉड्यूल: + `trustgraph-base/trustgraph/api/flow.py` + `trustgraph-base/trustgraph/api/socket_client.py` + +### डेटा मॉडल + +#### एम्बेडिंग्स रिक्वेस्ट + +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +उपयोग: +एकल पाठ: `EmbeddingsRequest(texts=["hello world"])` +बैच: `EmbeddingsRequest(texts=["text1", "text2", "text3"])` + +#### एम्बेडिंग रिस्पांस + +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +प्रतिक्रिया संरचना: +`vectors[i]` में `texts[i]` के लिए वेक्टर सेट शामिल है। +प्रत्येक वेक्टर सेट `list[list[float]]` होता है (मॉडल प्रत्येक पाठ के लिए कई वेक्टर वापस कर सकते हैं)। +उदाहरण: 3 पाठ → `vectors` में 3 प्रविष्टियाँ हैं, जिनमें से प्रत्येक में उस पाठ के एम्बेडिंग होते हैं। + +### एपीआई + +#### एम्बेडिंगक्लाइंट + +```python +class EmbeddingsClient(RequestResponse): + async def embed( + self, + texts: list[str], + timeout: float = 300, + ) -> list[list[list[float]]]: + """ + Embed one or more texts in a single request. + + Args: + texts: List of texts to embed + timeout: Timeout for the operation + + Returns: + List of vector sets, one per input text + """ + resp = await self.request( + EmbeddingsRequest(texts=texts), + timeout=timeout + ) + if resp.error: + raise RuntimeError(resp.error.message) + return resp.vectors +``` + +#### एपीआई गेटवे एम्बेडिंग एंडपॉइंट + +अपडेटेड एंडपॉइंट जो सिंगल या बैच एम्बेडिंग को सपोर्ट करता है: + +``` +POST /api/v1/embeddings +Content-Type: application/json + +{ + "texts": ["text1", "text2", "text3"], + "flow_id": "default" +} + +Response: +{ + "vectors": [ + [[0.1, 0.2, ...]], + [[0.3, 0.4, ...]], + [[0.5, 0.6, ...]] + ] +} +``` + +### कार्यान्वयन विवरण + +#### चरण 1: स्कीमा परिवर्तन + +**एम्बेडिंग रिक्वेस्ट:** +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +**एम्बेडिंग रिस्पांस:** +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +**अपडेटेड एम्बेडिंगसर्विस.ऑन_रिक्वेस्ट:** +```python +async def on_request(self, msg, consumer, flow): + request = msg.value() + id = msg.properties()["id"] + model = flow("model") + + vectors = await self.on_embeddings(request.texts, model=model) + response = EmbeddingsResponse(error=None, vectors=vectors) + + await flow("response").send(response, properties={"id": id}) +``` + +#### चरण 2: फास्टएम्बेड प्रोसेसर अपडेट + +**वर्तमान (अकुशल):** +```python +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + vecs = self.embeddings.embed([text]) # Batch of 1 + return [v.tolist() for v in vecs] +``` + +**अद्यतन:** +```python +async def on_embeddings(self, texts: list[str], model=None): + """Embed texts - processes all texts in single model call""" + if not texts: + return [] + + use_model = model or self.default_model + self._load_model(use_model) + + # FastEmbed handles the full batch efficiently + all_vecs = list(self.embeddings.embed(texts)) + + # Return list of vector sets, one per input text + return [[v.tolist()] for v in all_vecs] +``` + +#### चरण 3: ग्राफ एम्बेडिंग सेवा अपडेट + +**वर्तमान (सीरियल):** +```python +async def on_message(self, msg, consumer, flow): + entities = [] + for entity in v.entities: + vectors = await flow("embeddings-request").embed(text=entity.context) + entities.append(EntityEmbeddings(...)) +``` + +**अद्यतन (बैच):** +```python +async def on_message(self, msg, consumer, flow): + # Collect all contexts + contexts = [entity.context for entity in v.entities] + + # Single batch embedding call + all_vectors = await flow("embeddings-request").embed(texts=contexts) + + # Pair results with entities + entities = [ + EntityEmbeddings( + entity=entity.entity, + vectors=vectors[0], # First vector from the set + chunk_id=entity.chunk_id, + ) + for entity, vectors in zip(v.entities, all_vectors) + ] +``` + +#### चरण 4: पंक्ति एम्बेडिंग सेवा अपडेट + +**वर्तमान (क्रमिक):** +```python +for text, (index_name, index_value) in texts_to_embed.items(): + vectors = await flow("embeddings-request").embed(text=text) + embeddings_list.append(RowIndexEmbedding(...)) +``` + +**अद्यतन (बैच):** +```python +# Collect texts and metadata +texts = list(texts_to_embed.keys()) +metadata = list(texts_to_embed.values()) + +# Single batch embedding call +all_vectors = await flow("embeddings-request").embed(texts=texts) + +# Pair results +embeddings_list = [ + RowIndexEmbedding( + index_name=meta[0], + index_value=meta[1], + text=text, + vectors=vectors[0] # First vector from the set + ) + for text, meta, vectors in zip(texts, metadata, all_vectors) +] +``` + +#### चरण 5: कमांड-लाइन टूल में सुधार + +**अद्यतन कमांड-लाइन इंटरफ़ेस:** +```python +def main(): + parser = argparse.ArgumentParser(...) + + parser.add_argument( + 'text', + nargs='*', # Zero or more texts + help='Text(s) to convert to embedding vectors', + ) + + parser.add_argument( + '-f', '--file', + help='File containing texts (one per line)', + ) + + parser.add_argument( + '--batch-size', + type=int, + default=32, + help='Batch size for processing (default: 32)', + ) +``` + +उपयोग: +```bash +# Single text (existing) +tg-invoke-embeddings "hello world" + +# Multiple texts +tg-invoke-embeddings "text one" "text two" "text three" + +# From file +tg-invoke-embeddings -f texts.txt --batch-size 64 +``` + +#### चरण 6: पायथन एसडीके में सुधार + +**फ्लोइंस्टेंस (एचटीटीपी क्लाइंट):** + +```python +class FlowInstance: + def embeddings(self, texts: list[str]) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + input = {"texts": texts} + return self.request("service/embeddings", input)["vectors"] +``` + +**सॉकेटफ्लोइंस्टेंस (वेबसोकेट क्लाइंट):** + +```python +class SocketFlowInstance: + def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts via WebSocket. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + request = {"texts": texts} + response = self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) + return response["vectors"] +``` + +**एसडीके उपयोग के उदाहरण:** + +```python +# Single text +vectors = flow.embeddings(["hello world"]) +print(f"Dimensions: {len(vectors[0][0])}") + +# Batch embedding +texts = ["text one", "text two", "text three"] +all_vectors = flow.embeddings(texts) + +# Process results +for text, vecs in zip(texts, all_vectors): + print(f"{text}: {len(vecs[0])} dimensions") +``` + +## सुरक्षा संबंधी विचार + +**अनुरोध आकार सीमाएँ**: संसाधनों की कमी को रोकने के लिए अधिकतम बैच आकार लागू करें। +**समय-सीमा प्रबंधन**: बैच आकार के लिए समय-सीमा को उचित रूप से समायोजित करें। +**मेमोरी सीमाएँ**: बड़े बैचों के लिए मेमोरी उपयोग की निगरानी करें। +**इनपुट सत्यापन**: प्रसंस्करण से पहले बैच में सभी पाठों को मान्य करें। + +## प्रदर्शन संबंधी विचार + +### अपेक्षित सुधार + +**थ्रूपुट:** +एकल-पाठ: ~10-50 पाठ/सेकंड (मॉडल के आधार पर) +बैच (आकार 32): ~200-500 पाठ/सेकंड (5-10 गुना सुधार) + +**प्रति पाठ विलंबता:** +एकल-पाठ: प्रति पाठ 50-200ms +बैच (आकार 32): प्रति पाठ 5-20ms (औसत) + +**सेवा-विशिष्ट सुधार:** + +| सेवा | वर्तमान | बैच | सुधार | +|---------|---------|---------|-------------| +| ग्राफ एम्बेडिंग (50 इकाइयाँ) | 5-10s | 0.5-1s | 5-10x | +| पंक्ति एम्बेडिंग (100 पाठ) | 10-20s | 1-2s | 5-10x | +| दस्तावेज़ इनपुट (1000 खंड) | 100-200s | 10-30s | 5-10x | + +### कॉन्फ़िगरेशन पैरामीटर + +```python +# Recommended defaults +DEFAULT_BATCH_SIZE = 32 +MAX_BATCH_SIZE = 128 +BATCH_TIMEOUT_MULTIPLIER = 2.0 +``` + +## परीक्षण रणनीति + +### यूनिट परीक्षण +सिंगल टेक्स्ट एम्बेडिंग (पिछड़ा संगतता) +खाली बैच हैंडलिंग +अधिकतम बैच आकार का प्रवर्तन +आंशिक बैच विफलताओं के लिए त्रुटि हैंडलिंग + +### एकीकरण परीक्षण +पल्सर के माध्यम से एंड-टू-एंड बैच एम्बेडिंग +ग्राफ एम्बेडिंग सेवा बैच प्रसंस्करण +रो एम्बेडिंग सेवा बैच प्रसंस्करण +एपीआई गेटवे बैच एंडपॉइंट + +### प्रदर्शन परीक्षण +सिंगल बनाम बैच थ्रूपुट का बेंचमार्क +विभिन्न बैच आकारों के तहत मेमोरी उपयोग +विलंबता वितरण विश्लेषण + +## माइग्रेशन योजना + +यह एक ब्रेकिंग चेंज रिलीज़ है। सभी चरण एक साथ लागू किए गए हैं। + +### चरण 1: स्कीमा परिवर्तन +EmbeddingsRequest में `text: str` को `texts: list[str]` से बदलें +EmbeddingsResponse में `vectors` प्रकार को `list[list[list[float]]]` में बदलें + +### चरण 2: प्रोसेसर अपडेट +FastEmbed और Ollama प्रोसेसर में `on_embeddings` हस्ताक्षर को अपडेट करें +सिंगल मॉडल कॉल में पूरा बैच संसाधित करें + +### चरण 3: क्लाइंट अपडेट +`EmbeddingsClient.embed()` को `texts: list[str]` स्वीकार करने के लिए अपडेट करें + +### चरण 4: कॉलर अपडेट +graph_embeddings को बैच एंटिटी संदर्भों के लिए अपडेट करें +row_embeddings को बैच इंडेक्स टेक्स्ट के लिए अपडेट करें +document_embeddings को नए स्कीमा का उपयोग करने के लिए अपडेट करें +CLI टूल को अपडेट करें + +### चरण 5: एपीआई गेटवे +नए स्कीमा के लिए एम्बेडिंग एंडपॉइंट को अपडेट करें + +### चरण 6: पायथन SDK +`FlowInstance.embeddings()` हस्ताक्षर को अपडेट करें +`SocketFlowInstance.embeddings()` हस्ताक्षर को अपडेट करें + +## खुले प्रश्न + +**बड़े बैचों का स्ट्रीमिंग**: क्या हमें बहुत बड़े बैचों (>100 टेक्स्ट) के लिए स्ट्रीमिंग परिणामों का समर्थन करना चाहिए? +**प्रदाता-विशिष्ट सीमाएँ**: हमें विभिन्न अधिकतम बैच आकारों वाले प्रदाताओं को कैसे संभालना चाहिए? +**आंशिक विफलता हैंडलिंग**: यदि बैच में एक टेक्स्ट विफल हो जाता है, तो क्या हमें पूरे बैच को विफल करना चाहिए या आंशिक परिणाम लौटाने चाहिए? +**डॉक्यूमेंट एम्बेडिंग बैचिंग**: क्या हमें कई चंक संदेशों में बैच करना चाहिए या प्रति-संदेश प्रसंस्करण बनाए रखना चाहिए? + +## संदर्भ + +[FastEmbed Documentation](https://github.com/qdrant/fastembed) +[Ollama Embeddings API](https://github.com/ollama/ollama) +[EmbeddingsService Implementation](trustgraph-base/trustgraph/base/embeddings_service.py) +[GraphRAG Performance Optimization](graphrag-performance-optimization.md) diff --git a/docs/tech-specs/embeddings-batch-processing.pt.md b/docs/tech-specs/embeddings-batch-processing.pt.md new file mode 100644 index 00000000..41373b74 --- /dev/null +++ b/docs/tech-specs/embeddings-batch-processing.pt.md @@ -0,0 +1,667 @@ +# Especificação Técnica de Processamento em Lote de Embeddings + +## Visão Geral + +Esta especificação descreve otimizações para o serviço de embeddings para suportar o processamento em lote de vários textos em um único pedido. A implementação atual processa um texto por vez, perdendo os benefícios de desempenho significativos que os modelos de embedding oferecem ao processar lotes. + +1. **Ineficiência no Processamento de Texto Único**: A implementação atual envolve textos únicos em uma lista, subutilizando as capacidades de lote do FastEmbed. +2. **Sobrecarga de Pedido por Texto**: Cada texto requer uma viagem de ida e volta separada do Pulsar. +3. **Ineficiência na Inferência do Modelo**: Os modelos de embedding têm uma sobrecarga fixa por lote; lotes pequenos desperdiçam recursos de GPU/CPU. +4. **Processamento Serial nos Clientes**: Serviços importantes fazem loop sobre itens e chamam embeddings um de cada vez. + +## Objetivos + +**Suporte para API de Lote**: Permitir o processamento de vários textos em um único pedido. +**Compatibilidade com Versões Anteriores**: Manter o suporte para pedidos de texto único. +**Melhora Significativa no Desempenho**: Almejar uma melhora de desempenho de 5 a 10 vezes para operações em lote. +**Latência Reduzida por Texto**: Diminuir a latência amortizada ao incorporar vários textos. +**Eficiência de Memória**: Processar lotes sem consumo excessivo de memória. +**Independente do Provedor**: Suportar o processamento em lote em FastEmbed, Ollama e outros provedores. +**Migração do Cliente**: Atualizar todos os clientes de embedding para usar a API de lote sempre que for benéfico. + +## Contexto + +### Implementação Atual - Serviço de Embeddings + +A implementação de embeddings em `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` apresenta uma ineficiência de desempenho significativa: + +```python +# fastembed/processor.py line 56 +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + + vecs = self.embeddings.embed([text]) # Single text wrapped in list + + return [v.tolist() for v in vecs] +``` + +**Problemas:** + +1. **Tamanho do Lote 1**: O método `embed()` do FastEmbed é otimizado para processamento em lote, mas sempre o chamamos com `[text]` - um lote de tamanho 1. + +2. **Sobrecarga por Requisição**: Cada solicitação de incorporação incorre em: + Serialização/desserialização de mensagens Pulsar + Latência de ida e volta da rede + Sobrecarga de inicialização da inferência do modelo + Sobrecarga de agendamento assíncrono do Python + +3. **Limitação do Esquema**: O esquema `EmbeddingsRequest` suporta apenas um único texto: + ```python + @dataclass + class EmbeddingsRequest: + text: str = "" # Single text only + ``` + +### Clientes Atuais - Processamento Serial + +#### 1. Gateway de API + +**Arquivo:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +O gateway aceita solicitações de incorporação de texto único via HTTP/WebSocket e as encaminha para o serviço de incorporação. Atualmente, não existe um endpoint para processamento em lote. + +```python +class EmbeddingsRequestor(ServiceRequestor): + # Handles single EmbeddingsRequest -> EmbeddingsResponse + request_schema=EmbeddingsRequest, # Single text only + response_schema=EmbeddingsResponse, +``` + +**Impacto:** Clientes externos (aplicativos web, scripts) devem fazer N requisições HTTP para incorporar N textos. + +#### 2. Serviço de Incorporação de Documentos + +**Arquivo:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +Processa blocos de documentos um de cada vez: + +```python +async def on_message(self, msg, consumer, flow): + v = msg.value() + + # Single chunk per request + resp = await flow("embeddings-request").request( + EmbeddingsRequest(text=v.chunk) + ) + vectors = resp.vectors +``` + +**Impacto:** Cada trecho de documento requer uma chamada de embedding separada. Um documento com 100 trechos = 100 requisições de embedding. + +#### 3. Serviço de Embeddings de Grafos + +**Arquivo:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + +Percorre as entidades e incorpora cada uma sequencialmente: + +```python +async def on_message(self, msg, consumer, flow): + for entity in v.entities: + # Serial embedding - one entity at a time + vectors = await flow("embeddings-request").embed( + text=entity.context + ) + entities.append(EntityEmbeddings( + entity=entity.entity, + vectors=vectors, + chunk_id=entity.chunk_id, + )) +``` + +**Impacto:** Uma mensagem com 50 entidades = 50 solicitações de incorporação serial. Isso é um grande gargalo durante a construção do grafo de conhecimento. + +#### 4. Serviço de Incorporação de Linhas + +**Arquivo:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + +Percorre textos únicos e incorpora cada um serialmente: + +```python +async def on_message(self, msg, consumer, flow): + for text, (index_name, index_value) in texts_to_embed.items(): + # Serial embedding - one text at a time + vectors = await flow("embeddings-request").embed(text=text) + + embeddings_list.append(RowIndexEmbedding( + index_name=index_name, + index_value=index_value, + text=text, + vectors=vectors + )) +``` + +**Impacto:** Processar uma tabela com 100 valores indexados únicos = 100 solicitações de incorporação seriais. + +#### 5. EmbeddingsClient (Cliente Base) + +**Arquivo:** `trustgraph-base/trustgraph/base/embeddings_client.py` + +O cliente usado por todos os processadores de fluxo suporta apenas a incorporação de texto único: + +```python +class EmbeddingsClient(RequestResponse): + async def embed(self, text, timeout=30): + resp = await self.request( + EmbeddingsRequest(text=text), # Single text + timeout=timeout + ) + return resp.vectors +``` + +**Impacto:** Todos os clientes que utilizam este componente estão limitados a operações de texto único. + +#### 6. Ferramentas de Linha de Comando + +**Arquivo:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +A ferramenta de linha de comando aceita um único argumento de texto: + +```python +def query(url, flow_id, text, token=None): + result = flow.embeddings(text=text) # Single text + vectors = result.get("vectors", []) +``` + +**Impacto:** Os usuários não podem realizar incorporações em lote a partir da linha de comando. O processamento de um arquivo de textos requer N invocações. + +#### 7. SDK Python + +O SDK Python fornece duas classes de cliente para interagir com os serviços da TrustGraph. Ambas suportam apenas a incorporação de um único texto. + +**Arquivo:** `trustgraph-base/trustgraph/api/flow.py` + +```python +class FlowInstance: + def embeddings(self, text): + """Get embeddings for a single text""" + input = {"text": text} + return self.request("service/embeddings", input)["vectors"] +``` + +**Arquivo:** `trustgraph-base/trustgraph/api/socket_client.py` + +```python +class SocketFlowInstance: + def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]: + """Get embeddings for a single text via WebSocket""" + request = {"text": text} + return self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) +``` + +**Impacto:** Desenvolvedores Python que usam o SDK precisam iterar sobre textos e fazer N chamadas de API separadas. Não existe suporte para processamento em lote de embeddings para usuários do SDK. + +### Impacto no Desempenho + +Para ingestão típica de documentos (1000 trechos de texto): +**Atual:** 1000 requisições separadas, 1000 chamadas de inferência de modelo +**Em lote (batch_size=32):** 32 requisições, 32 chamadas de inferência de modelo (redução de 96,8%) + +Para embedding de grafos (mensagem com 50 entidades): +**Atual:** 50 chamadas `await` sequenciais, ~5-10 segundos +**Em lote:** 1-2 chamadas em lote, ~0,5-1 segundo (melhora de 5-10x) + +Bibliotecas como FastEmbed e similares alcançam escalabilidade quase linear no throughput com o tamanho do lote, até os limites do hardware (tipicamente 32-128 textos por lote). + +## Design Técnico + +### Arquitetura + +A otimização de processamento em lote de embeddings requer alterações nos seguintes componentes: + +#### 1. **Aprimoramento do Esquema** + Estender `EmbeddingsRequest` para suportar múltiplos textos + Estender `EmbeddingsResponse` para retornar múltiplos conjuntos de vetores + Manter a compatibilidade retroativa com requisições de texto único + + Módulo: `trustgraph-base/trustgraph/schema/services/llm.py` + +#### 2. **Aprimoramento do Serviço Base** + Atualizar `EmbeddingsService` para lidar com requisições em lote + Adicionar configuração do tamanho do lote + Implementar tratamento de requisições com suporte a lote + + Módulo: `trustgraph-base/trustgraph/base/embeddings_service.py` + +#### 3. **Atualizações do Processador do Provedor** + Atualizar o processador FastEmbed para passar o lote completo para `embed()` + Atualizar o processador Ollama para lidar com lotes (se suportado) + Adicionar processamento sequencial como fallback para provedores sem suporte a lote + + Módulos: + `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` + `trustgraph-flow/trustgraph/embeddings/ollama/processor.py` + +#### 4. **Aprimoramento do Cliente** + Adicionar método de embedding em lote para `EmbeddingsClient` + Suportar APIs de texto único e em lote + Adicionar agrupamento automático para grandes entradas + + Módulo: `trustgraph-base/trustgraph/base/embeddings_client.py` + +#### 5. **Atualizações do Chamador - Processadores de Fluxo** + Atualizar `graph_embeddings` para agrupar contextos de entidades + Atualizar `row_embeddings` para agrupar textos de índice + Atualizar `document_embeddings` se o agrupamento de mensagens for viável + + Módulos: + `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +#### 6. **Aprimoramento do Gateway de API** + Adicionar endpoint de embedding em lote + Suportar array de textos no corpo da requisição + + Módulo: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +#### 7. **Aprimoramento da Ferramenta de Linha de Comando (CLI)** + Adicionar suporte para múltiplos textos ou entrada de arquivo + Adicionar parâmetro de tamanho do lote + + Módulo: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +#### 8. **Aprimoramento do SDK Python** + Adicionar método `embeddings_batch()` para `FlowInstance` + Adicionar método `embeddings_batch()` para `SocketFlowInstance` + Suportar APIs de texto único e em lote para usuários do SDK + + Módulos: + `trustgraph-base/trustgraph/api/flow.py` + `trustgraph-base/trustgraph/api/socket_client.py` + +### Modelos de Dados + +#### EmbeddingsRequest + +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +Uso: +Texto único: `EmbeddingsRequest(texts=["hello world"])` +Lote: `EmbeddingsRequest(texts=["text1", "text2", "text3"])` + +#### EmbeddingsResponse + +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +Estrutura da resposta: +`vectors[i]` contém o conjunto de vetores para `texts[i]` +Cada conjunto de vetores é `list[list[float]]` (os modelos podem retornar vários vetores por texto) +Exemplo: 3 textos → `vectors` tem 3 entradas, cada uma contendo os embeddings desse texto + +### APIs + +#### EmbeddingsClient + +```python +class EmbeddingsClient(RequestResponse): + async def embed( + self, + texts: list[str], + timeout: float = 300, + ) -> list[list[list[float]]]: + """ + Embed one or more texts in a single request. + + Args: + texts: List of texts to embed + timeout: Timeout for the operation + + Returns: + List of vector sets, one per input text + """ + resp = await self.request( + EmbeddingsRequest(texts=texts), + timeout=timeout + ) + if resp.error: + raise RuntimeError(resp.error.message) + return resp.vectors +``` + +#### Endpoint de Incorporação do Gateway de API + +Endpoint atualizado que suporta incorporação única ou em lote: + +``` +POST /api/v1/embeddings +Content-Type: application/json + +{ + "texts": ["text1", "text2", "text3"], + "flow_id": "default" +} + +Response: +{ + "vectors": [ + [[0.1, 0.2, ...]], + [[0.3, 0.4, ...]], + [[0.5, 0.6, ...]] + ] +} +``` + +### Detalhes de Implementação + +#### Fase 1: Alterações no Esquema + +**EmbeddingsRequest:** +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +**EmbeddingsResponse:** +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +**Atualizado EmbeddingsService.on_request:** +```python +async def on_request(self, msg, consumer, flow): + request = msg.value() + id = msg.properties()["id"] + model = flow("model") + + vectors = await self.on_embeddings(request.texts, model=model) + response = EmbeddingsResponse(error=None, vectors=vectors) + + await flow("response").send(response, properties={"id": id}) +``` + +#### Fase 2: Atualização do Processador FastEmbed + +**Atual (Ineficiente):** +```python +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + vecs = self.embeddings.embed([text]) # Batch of 1 + return [v.tolist() for v in vecs] +``` + +**Atualizado:** +```python +async def on_embeddings(self, texts: list[str], model=None): + """Embed texts - processes all texts in single model call""" + if not texts: + return [] + + use_model = model or self.default_model + self._load_model(use_model) + + # FastEmbed handles the full batch efficiently + all_vecs = list(self.embeddings.embed(texts)) + + # Return list of vector sets, one per input text + return [[v.tolist()] for v in all_vecs] +``` + +#### Fase 3: Atualização do Serviço de Incorporação de Grafos + +**Atual (Serial):** +```python +async def on_message(self, msg, consumer, flow): + entities = [] + for entity in v.entities: + vectors = await flow("embeddings-request").embed(text=entity.context) + entities.append(EntityEmbeddings(...)) +``` + +**Atualizado (Lote):** +```python +async def on_message(self, msg, consumer, flow): + # Collect all contexts + contexts = [entity.context for entity in v.entities] + + # Single batch embedding call + all_vectors = await flow("embeddings-request").embed(texts=contexts) + + # Pair results with entities + entities = [ + EntityEmbeddings( + entity=entity.entity, + vectors=vectors[0], # First vector from the set + chunk_id=entity.chunk_id, + ) + for entity, vectors in zip(v.entities, all_vectors) + ] +``` + +#### Fase 4: Atualização do Serviço de Incorporação de Dados + +**Atual (Serial):** +```python +for text, (index_name, index_value) in texts_to_embed.items(): + vectors = await flow("embeddings-request").embed(text=text) + embeddings_list.append(RowIndexEmbedding(...)) +``` + +**Atualizado (Lote):** +```python +# Collect texts and metadata +texts = list(texts_to_embed.keys()) +metadata = list(texts_to_embed.values()) + +# Single batch embedding call +all_vectors = await flow("embeddings-request").embed(texts=texts) + +# Pair results +embeddings_list = [ + RowIndexEmbedding( + index_name=meta[0], + index_value=meta[1], + text=text, + vectors=vectors[0] # First vector from the set + ) + for text, meta, vectors in zip(texts, metadata, all_vectors) +] +``` + +#### Fase 5: Melhoria da Ferramenta de Linha de Comando (CLI) + +**CLI Atualizado:** +```python +def main(): + parser = argparse.ArgumentParser(...) + + parser.add_argument( + 'text', + nargs='*', # Zero or more texts + help='Text(s) to convert to embedding vectors', + ) + + parser.add_argument( + '-f', '--file', + help='File containing texts (one per line)', + ) + + parser.add_argument( + '--batch-size', + type=int, + default=32, + help='Batch size for processing (default: 32)', + ) +``` + +Uso: +```bash +# Single text (existing) +tg-invoke-embeddings "hello world" + +# Multiple texts +tg-invoke-embeddings "text one" "text two" "text three" + +# From file +tg-invoke-embeddings -f texts.txt --batch-size 64 +``` + +#### Fase 6: Melhoria do SDK Python + +**FlowInstance (cliente HTTP):** + +```python +class FlowInstance: + def embeddings(self, texts: list[str]) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + input = {"texts": texts} + return self.request("service/embeddings", input)["vectors"] +``` + +**SocketFlowInstance (cliente WebSocket):** + +```python +class SocketFlowInstance: + def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts via WebSocket. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + request = {"texts": texts} + response = self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) + return response["vectors"] +``` + +**Exemplos de uso do SDK:** + +```python +# Single text +vectors = flow.embeddings(["hello world"]) +print(f"Dimensions: {len(vectors[0][0])}") + +# Batch embedding +texts = ["text one", "text two", "text three"] +all_vectors = flow.embeddings(texts) + +# Process results +for text, vecs in zip(texts, all_vectors): + print(f"{text}: {len(vecs[0])} dimensions") +``` + +## Considerações de Segurança + +**Limites de Tamanho da Requisição**: Impor o tamanho máximo do lote para evitar o esgotamento de recursos. +**Tratamento de Tempo Limite (Timeout)**: Ajustar os tempos limite de acordo com o tamanho do lote. +**Limites de Memória**: Monitorar o uso de memória para grandes lotes. +**Validação de Entrada**: Validar todos os textos no lote antes do processamento. + +## Considerações de Desempenho + +### Melhorias Esperadas + +**Taxa de Transferência (Throughput):** +Texto único: ~10-50 textos/segundo (dependendo do modelo) +Lote (tamanho 32): ~200-500 textos/segundo (melhora de 5 a 10 vezes) + +**Latência por Texto:** +Texto único: 50-200ms por texto +Lote (tamanho 32): 5-20ms por texto (média) + +**Melhorias Específicas do Serviço:** + +| Serviço | Atual | Em Lote | Melhoria | +|---------|---------|---------|-------------| +| Incorporações de Grafos (50 entidades) | 5-10s | 0,5-1s | 5-10x | +| Incorporações de Linhas (100 textos) | 10-20s | 1-2s | 5-10x | +| Ingestão de Documentos (1000 fragmentos) | 100-200s | 10-30s | 5-10x | + +### Parâmetros de Configuração + +```python +# Recommended defaults +DEFAULT_BATCH_SIZE = 32 +MAX_BATCH_SIZE = 128 +BATCH_TIMEOUT_MULTIPLIER = 2.0 +``` + +## Estratégia de Testes + +### Testes Unitários +Incorporação de texto única (compatibilidade com versões anteriores) +Tratamento de lotes vazios +Imposição do tamanho máximo do lote +Tratamento de erros para falhas parciais do lote + +### Testes de Integração +Incorporação de lote de ponta a ponta através do Pulsar +Processamento de lote do serviço de incorporação de grafos +Processamento de lote do serviço de incorporação de linhas +Endpoint de lote do gateway de API + +### Testes de Desempenho +Comparação de benchmark de taxa de transferência única versus lote +Uso de memória sob vários tamanhos de lote +Análise da distribuição de latência + +## Plano de Migração + +Esta é uma versão que introduz alterações significativas. Todas as fases são implementadas juntas. + +### Fase 1: Alterações no Esquema +Substituir `text: str` por `texts: list[str]` em EmbeddingsRequest +Alterar o tipo de `vectors` para `list[list[list[float]]]` em EmbeddingsResponse + +### Fase 2: Atualizações do Processador +Atualizar a assinatura de `on_embeddings` nos processadores FastEmbed e Ollama +Processar o lote completo em uma única chamada de modelo + +### Fase 3: Atualizações do Cliente +Atualizar `EmbeddingsClient.embed()` para aceitar `texts: list[str]` + +### Fase 4: Atualizações do Chamador +Atualizar graph_embeddings para incorporar contextos de entidades em lote +Atualizar row_embeddings para incorporar textos de índice em lote +Atualizar document_embeddings para usar o novo esquema +Atualizar a ferramenta de linha de comando (CLI) + +### Fase 5: Gateway de API +Atualizar o endpoint de incorporação para o novo esquema + +### Fase 6: SDK Python +Atualizar a assinatura de `FlowInstance.embeddings()` +Atualizar a assinatura de `SocketFlowInstance.embeddings()` + +## Perguntas Abertas + +**Incorporação de Lotes Grandes em Streaming**: Devemos suportar o streaming de resultados para lotes muito grandes (>100 textos)? +**Limites Específicos do Provedor**: Como devemos lidar com provedores com tamanhos máximos de lote diferentes? +**Tratamento de Falhas Parciais**: Se um texto em um lote falhar, devemos falhar o lote inteiro ou retornar resultados parciais? +**Incorporação em Lote de Documentos**: Devemos incorporar em lote em várias mensagens de Chunk ou manter o processamento por mensagem? + +## Referências + +[Documentação do FastEmbed](https://github.com/qdrant/fastembed) +[API de Incorporação do Ollama](https://github.com/ollama/ollama) +[Implementação do Serviço de Incorporação](trustgraph-base/trustgraph/base/embeddings_service.py) +[Otimização de Desempenho do GraphRAG](graphrag-performance-optimization.md) diff --git a/docs/tech-specs/embeddings-batch-processing.ru.md b/docs/tech-specs/embeddings-batch-processing.ru.md new file mode 100644 index 00000000..ec3d7bab --- /dev/null +++ b/docs/tech-specs/embeddings-batch-processing.ru.md @@ -0,0 +1,667 @@ +# Техническая спецификация пакетной обработки эмбеддингов + +## Обзор + +Эта спецификация описывает оптимизации для сервиса эмбеддингов, предназначенные для поддержки пакетной обработки нескольких текстов в одном запросе. Текущая реализация обрабатывает один текст за раз, что не позволяет использовать значительные преимущества, которые предоставляют модели эмбеддингов при обработке пакетов. + +1. **Неэффективность обработки одного текста**: Текущая реализация оборачивает отдельные тексты в список, что не позволяет в полной мере использовать возможности пакетной обработки FastEmbed. +2. **Накладные расходы на запрос для каждого текста**: Для каждого текста требуется отдельная передача сообщения Pulsar. +3. **Неэффективность вывода модели**: Модели эмбеддингов имеют фиксированные накладные расходы на пакет; небольшие пакеты приводят к неэффективному использованию ресурсов GPU/CPU. +4. **Последовательная обработка в вызывающих сервисах**: Основные сервисы перебирают элементы и вызывают эмбеддинги по одному. + +## Цели + +**Поддержка пакетного API**: Обеспечить возможность обработки нескольких текстов в одном запросе. +**Обратная совместимость**: Сохранить поддержку запросов для обработки одного текста. +**Значительное повышение производительности**: Стремиться к увеличению производительности в 5-10 раз для массовых операций. +**Снижение задержки на текст**: Уменьшить среднюю задержку при создании эмбеддингов для нескольких текстов. +**Эффективность использования памяти**: Обрабатывать пакеты без чрезмерного потребления памяти. +**Независимость от провайдера**: Поддерживать пакетную обработку для FastEmbed, Ollama и других провайдеров. +**Миграция вызывающих сервисов**: Обновить все сервисы, вызывающие эмбеддинги, для использования пакетного API, где это целесообразно. + +## Контекст + +### Текущая реализация - Сервис эмбеддингов + +Реализация эмбеддингов в `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` демонстрирует значительную неэффективность: + +```python +# fastembed/processor.py line 56 +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + + vecs = self.embeddings.embed([text]) # Single text wrapped in list + + return [v.tolist() for v in vecs] +``` + +**Проблемы:** + +1. **Размер пакета 1**: Метод `embed()` FastEmbed оптимизирован для пакетной обработки, но мы всегда вызываем его с `[text]` - пакетом размера 1. + +2. **Накладные расходы на каждый запрос**: Каждый запрос на получение эмбеддингов влечет за собой: + Сериализацию/десериализацию сообщения Pulsar. + Задержку сетевого обмена. + Накладные расходы на запуск инференса модели. + Накладные расходы на асинхронное планирование Python. + +3. **Ограничение схемы**: Схема `EmbeddingsRequest` поддерживает только один текстовый фрагмент: + ```python + @dataclass + class EmbeddingsRequest: + text: str = "" # Single text only + ``` + +### Текущие вызывающие стороны - последовательная обработка + +#### 1. API-шлюз + +**Файл:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +Шлюз принимает запросы на однострочное создание векторных представлений через HTTP/WebSocket и перенаправляет их в сервис создания векторных представлений. В настоящее время нет пакетного интерфейса. + +```python +class EmbeddingsRequestor(ServiceRequestor): + # Handles single EmbeddingsRequest -> EmbeddingsResponse + request_schema=EmbeddingsRequest, # Single text only + response_schema=EmbeddingsResponse, +``` + +**Влияние:** Внешние клиенты (веб-приложения, скрипты) должны выполнять N HTTP-запросов для встраивания N текстов. + +#### 2. Сервис встраивания документов + +**Файл:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +Обрабатывает фрагменты документов по одному. + +```python +async def on_message(self, msg, consumer, flow): + v = msg.value() + + # Single chunk per request + resp = await flow("embeddings-request").request( + EmbeddingsRequest(text=v.chunk) + ) + vectors = resp.vectors +``` + +**Влияние:** Каждый фрагмент документа требует отдельного вызова для создания эмбеддинга. Документ, состоящий из 100 фрагментов, = 100 запросов на создание эмбеддингов. + +#### 3. Сервис создания графовых эмбеддингов + +**Файл:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + +Выполняет итерации по сущностям и создает эмбеддинг для каждой из них последовательно: + +```python +async def on_message(self, msg, consumer, flow): + for entity in v.entities: + # Serial embedding - one entity at a time + vectors = await flow("embeddings-request").embed( + text=entity.context + ) + entities.append(EntityEmbeddings( + entity=entity.entity, + vectors=vectors, + chunk_id=entity.chunk_id, + )) +``` + +**Влияние:** Сообщение, содержащее 50 сущностей, приводит к 50 последовательным запросам на создание векторных представлений. Это серьезное препятствие при построении графа знаний. + +#### 4. Сервис создания векторных представлений строк + +**Файл:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + +Выполняет итерации по уникальным текстам и создает векторное представление для каждого из них последовательно: + +```python +async def on_message(self, msg, consumer, flow): + for text, (index_name, index_value) in texts_to_embed.items(): + # Serial embedding - one text at a time + vectors = await flow("embeddings-request").embed(text=text) + + embeddings_list.append(RowIndexEmbedding( + index_name=index_name, + index_value=index_value, + text=text, + vectors=vectors + )) +``` + +**Влияние:** Обработка таблицы с 100 уникальными индексированными значениями = 100 последовательных запросов на создание векторных представлений. + +#### 5. EmbeddingsClient (Базовый клиент) + +**Файл:** `trustgraph-base/trustgraph/base/embeddings_client.py` + +Клиент, используемый всеми процессорами потоков, поддерживает только создание векторных представлений для одного текстового фрагмента: + +```python +class EmbeddingsClient(RequestResponse): + async def embed(self, text, timeout=30): + resp = await self.request( + EmbeddingsRequest(text=text), # Single text + timeout=timeout + ) + return resp.vectors +``` + +**Влияние:** Все клиенты, использующие этот компонент, ограничены операциями с одним текстовым фрагментом. + +#### 6. Инструменты командной строки + +**Файл:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +Инструмент командной строки принимает один текстовый аргумент: + +```python +def query(url, flow_id, text, token=None): + result = flow.embeddings(text=text) # Single text + vectors = result.get("vectors", []) +``` + +**Влияние:** Пользователи не могут выполнять пакетную вставку из командной строки. Обработка файла текстов требует N вызовов. + +#### 7. Python SDK + +Python SDK предоставляет два клиентских класса для взаимодействия со службами TrustGraph. Оба поддерживают только вставку одного текста. + +**Файл:** `trustgraph-base/trustgraph/api/flow.py` + +```python +class FlowInstance: + def embeddings(self, text): + """Get embeddings for a single text""" + input = {"text": text} + return self.request("service/embeddings", input)["vectors"] +``` + +**Файл:** `trustgraph-base/trustgraph/api/socket_client.py` + +```python +class SocketFlowInstance: + def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]: + """Get embeddings for a single text via WebSocket""" + request = {"text": text} + return self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) +``` + +**Влияние:** Разработчикам Python, использующим SDK, необходимо перебирать тексты и выполнять N отдельных API-запросов. Поддержка пакетной обработки векторов для пользователей SDK отсутствует. + +### Влияние на производительность + +Для типичного извлечения данных (1000 текстовых фрагментов): +**Текущая ситуация:** 1000 отдельных запросов, 1000 вызовов модели для получения векторов. +**Пакетная обработка (batch_size=32):** 32 запроса, 32 вызова модели для получения векторов (снижение на 96,8%). + +Для получения векторов графа (сообщение с 50 сущностями): +**Текущая ситуация:** 50 последовательных вызовов `await`, ~5-10 секунд. +**Пакетная обработка:** 1-2 пакетных вызова, ~0,5-1 секунда (улучшение в 5-10 раз). + +Библиотеки FastEmbed и аналогичные достигают почти линейного увеличения производительности при увеличении размера пакета до пределов аппаратного обеспечения (обычно 32-128 текстов на пакет). + +## Техническое проектирование + +### Архитектура + +Оптимизация пакетной обработки векторов требует изменений в следующих компонентах: + +#### 1. **Улучшение схемы данных** + Расширить `EmbeddingsRequest` для поддержки нескольких текстов. + Расширить `EmbeddingsResponse` для возврата нескольких наборов векторов. + Сохранить обратную совместимость с запросами для одного текста. + + Модуль: `trustgraph-base/trustgraph/schema/services/llm.py` + +#### 2. **Улучшение базового сервиса** + Обновить `EmbeddingsService` для обработки пакетных запросов. + Добавить конфигурацию размера пакета. + Реализовать обработку запросов с учетом пакетной обработки. + + Модуль: `trustgraph-base/trustgraph/base/embeddings_service.py` + +#### 3. **Обновления для процессоров провайдеров** + Обновить процессор FastEmbed для передачи полного пакета в `embed()`. + Обновить процессор Ollama для обработки пакетов (если поддерживается). + Добавить последовательную обработку в качестве запасного варианта для провайдеров, не поддерживающих пакетную обработку. + + Модули: + `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` + `trustgraph-flow/trustgraph/embeddings/ollama/processor.py` + +#### 4. **Улучшение клиентской библиотеки** + Добавить метод пакетной обработки векторов в `EmbeddingsClient`. + Поддерживать как одиночные, так и пакетные API. + Добавить автоматическую пакетную обработку для больших входных данных. + + Модуль: `trustgraph-base/trustgraph/base/embeddings_client.py` + +#### 5. **Обновления для вызывающего кода - процессоров потоков** + Обновить `graph_embeddings` для пакетной обработки контекстов сущностей. + Обновить `row_embeddings` для пакетной обработки текстов для индексации. + Обновить `document_embeddings`, если пакетная обработка сообщений возможна. + + Модули: + `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +#### 6. **Улучшение API-шлюза** + Добавить конечную точку для пакетной обработки векторов. + Поддерживать массив текстов в теле запроса. + + Модуль: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +#### 7. **Улучшение инструмента командной строки (CLI)** + Добавить поддержку нескольких текстов или ввода из файла. + Добавить параметр размера пакета. + + Модуль: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +#### 8. **Улучшение Python SDK** + Добавить метод `embeddings_batch()` в `FlowInstance`. + Добавить метод `embeddings_batch()` в `SocketFlowInstance`. + Поддерживать как одиночные, так и пакетные API для пользователей SDK. + + Модули: + `trustgraph-base/trustgraph/api/flow.py` + `trustgraph-base/trustgraph/api/socket_client.py` + +### Модели данных + +#### EmbeddingsRequest + +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +Использование: +Одиночный текст: `EmbeddingsRequest(texts=["hello world"])` +Пакетный режим: `EmbeddingsRequest(texts=["text1", "text2", "text3"])` + +#### EmbeddingsResponse + +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +Структура ответа: +`vectors[i]` содержит набор векторов для `texts[i]` +Каждый набор векторов имеет размер `list[list[float]]` (модели могут возвращать несколько векторов для одного текста) +Пример: 3 текста → `vectors` имеет 3 записи, каждая из которых содержит векторные представления этого текста + +### API + +#### EmbeddingsClient + +```python +class EmbeddingsClient(RequestResponse): + async def embed( + self, + texts: list[str], + timeout: float = 300, + ) -> list[list[list[float]]]: + """ + Embed one or more texts in a single request. + + Args: + texts: List of texts to embed + timeout: Timeout for the operation + + Returns: + List of vector sets, one per input text + """ + resp = await self.request( + EmbeddingsRequest(texts=texts), + timeout=timeout + ) + if resp.error: + raise RuntimeError(resp.error.message) + return resp.vectors +``` + +#### Конечная точка API Gateway для встраиваемых объектов + +Обновленная конечная точка, поддерживающая однократную или пакетную генерацию встраиваемых объектов: + +``` +POST /api/v1/embeddings +Content-Type: application/json + +{ + "texts": ["text1", "text2", "text3"], + "flow_id": "default" +} + +Response: +{ + "vectors": [ + [[0.1, 0.2, ...]], + [[0.3, 0.4, ...]], + [[0.5, 0.6, ...]] + ] +} +``` + +### Детали реализации + +#### Этап 1: Изменения схемы + +**EmbeddingsRequest:** +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +**Ответ Embeddings:** +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +**Обновлен класс EmbeddingsService.on_request:** +```python +async def on_request(self, msg, consumer, flow): + request = msg.value() + id = msg.properties()["id"] + model = flow("model") + + vectors = await self.on_embeddings(request.texts, model=model) + response = EmbeddingsResponse(error=None, vectors=vectors) + + await flow("response").send(response, properties={"id": id}) +``` + +#### Фаза 2: Обновление процессора FastEmbed + +**Текущая (неэффективная):** +```python +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + vecs = self.embeddings.embed([text]) # Batch of 1 + return [v.tolist() for v in vecs] +``` + +**Обновлено:** +```python +async def on_embeddings(self, texts: list[str], model=None): + """Embed texts - processes all texts in single model call""" + if not texts: + return [] + + use_model = model or self.default_model + self._load_model(use_model) + + # FastEmbed handles the full batch efficiently + all_vecs = list(self.embeddings.embed(texts)) + + # Return list of vector sets, one per input text + return [[v.tolist()] for v in all_vecs] +``` + +#### Фаза 3: Обновление сервиса графовых вложений + +**Текущая (последовательная):** +```python +async def on_message(self, msg, consumer, flow): + entities = [] + for entity in v.entities: + vectors = await flow("embeddings-request").embed(text=entity.context) + entities.append(EntityEmbeddings(...)) +``` + +**Обновлено (пакетно):** +```python +async def on_message(self, msg, consumer, flow): + # Collect all contexts + contexts = [entity.context for entity in v.entities] + + # Single batch embedding call + all_vectors = await flow("embeddings-request").embed(texts=contexts) + + # Pair results with entities + entities = [ + EntityEmbeddings( + entity=entity.entity, + vectors=vectors[0], # First vector from the set + chunk_id=entity.chunk_id, + ) + for entity, vectors in zip(v.entities, all_vectors) + ] +``` + +#### Фаза 4: Обновление сервиса встраивания данных. + +**Текущая (последовательная):** +```python +for text, (index_name, index_value) in texts_to_embed.items(): + vectors = await flow("embeddings-request").embed(text=text) + embeddings_list.append(RowIndexEmbedding(...)) +``` + +**Обновлено (пакетно):** +```python +# Collect texts and metadata +texts = list(texts_to_embed.keys()) +metadata = list(texts_to_embed.values()) + +# Single batch embedding call +all_vectors = await flow("embeddings-request").embed(texts=texts) + +# Pair results +embeddings_list = [ + RowIndexEmbedding( + index_name=meta[0], + index_value=meta[1], + text=text, + vectors=vectors[0] # First vector from the set + ) + for text, meta, vectors in zip(texts, metadata, all_vectors) +] +``` + +#### Фаза 5: Улучшение инструмента командной строки (CLI). + +**Обновленный CLI:** +```python +def main(): + parser = argparse.ArgumentParser(...) + + parser.add_argument( + 'text', + nargs='*', # Zero or more texts + help='Text(s) to convert to embedding vectors', + ) + + parser.add_argument( + '-f', '--file', + help='File containing texts (one per line)', + ) + + parser.add_argument( + '--batch-size', + type=int, + default=32, + help='Batch size for processing (default: 32)', + ) +``` + +Использование: +```bash +# Single text (existing) +tg-invoke-embeddings "hello world" + +# Multiple texts +tg-invoke-embeddings "text one" "text two" "text three" + +# From file +tg-invoke-embeddings -f texts.txt --batch-size 64 +``` + +#### Фаза 6: Улучшение SDK для Python + +**FlowInstance (HTTP-клиент):** + +```python +class FlowInstance: + def embeddings(self, texts: list[str]) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + input = {"texts": texts} + return self.request("service/embeddings", input)["vectors"] +``` + +**SocketFlowInstance (клиент WebSocket):** + +```python +class SocketFlowInstance: + def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts via WebSocket. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + request = {"texts": texts} + response = self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) + return response["vectors"] +``` + +**Примеры использования SDK:** + +```python +# Single text +vectors = flow.embeddings(["hello world"]) +print(f"Dimensions: {len(vectors[0][0])}") + +# Batch embedding +texts = ["text one", "text two", "text three"] +all_vectors = flow.embeddings(texts) + +# Process results +for text, vecs in zip(texts, all_vectors): + print(f"{text}: {len(vecs[0])} dimensions") +``` + +## Соображения безопасности + +**Ограничения на размер запроса**: Установите максимальный размер пакета для предотвращения исчерпания ресурсов. +**Обработка таймаутов**: Адаптируйте таймауты в соответствии с размером пакета. +**Ограничения памяти**: Отслеживайте использование памяти для больших пакетов. +**Проверка входных данных**: Проверяйте все тексты в пакете перед обработкой. + +## Соображения производительности + +### Ожидаемые улучшения + +**Производительность:** +Для одного текста: ~10-50 текстов/секунду (в зависимости от модели). +Для пакета (размер 32): ~200-500 текстов/секунду (улучшение в 5-10 раз). + +**Задержка на текст:** +Для одного текста: 50-200 мс на текст. +Для пакета (размер 32): 5-20 мс на текст (в среднем). + +**Улучшения для конкретных сервисов:** + +| Сервис | Текущее значение | Пакетный режим | Улучшение | +|---------|---------|---------|-------------| +| Векторные представления графов (50 сущностей) | 5-10 секунд | 0.5-1 секунда | 5-10x | +| Векторные представления строк (100 текстов) | 10-20 секунд | 1-2 секунды | 5-10x | +| Импорт документов (1000 фрагментов) | 100-200 секунд | 10-30 секунд | 5-10x | + +### Параметры конфигурации + +```python +# Recommended defaults +DEFAULT_BATCH_SIZE = 32 +MAX_BATCH_SIZE = 128 +BATCH_TIMEOUT_MULTIPLIER = 2.0 +``` + +## Стратегия тестирования + +### Модульное тестирование +Обработка однострочных вложений (обратная совместимость) +Обработка пустых пакетов +Применение максимального размера пакета +Обработка ошибок при частичных сбоях пакета + +### Интеграционное тестирование +Полная обработка пакетов через Pulsar +Обработка пакетов сервисом графовых вложений +Обработка пакетов сервисом строковых вложений +API-шлюз для пакетных операций + +### Тестирование производительности +Сравнение производительности при обработке отдельных элементов и пакетов +Использование памяти при различных размерах пакетов +Анализ распределения задержек + +## План миграции + +Это версия с критическими изменениями. Все этапы реализованы одновременно. + +### Этап 1: Изменения схемы +Заменить `text: str` на `texts: list[str]` в EmbeddingsRequest +Изменить тип `vectors` на `list[list[list[float]]]` в EmbeddingsResponse + +### Этап 2: Обновление процессоров +Обновить сигнатуру `on_embeddings` в процессорах FastEmbed и Ollama +Обрабатывать полный пакет за один вызов модели + +### Этап 3: Обновление клиентской части +Обновить `EmbeddingsClient.embed()` для приема `texts: list[str]` + +### Этап 4: Обновление вызывающего кода +Обновить graph_embeddings для пакетной обработки контекстов сущностей +Обновить row_embeddings для пакетной обработки текстов индекса +Обновить document_embeddings для использования новой схемы +Обновить инструмент командной строки + +### Этап 5: API-шлюз +Обновить конечную точку для вложений в соответствии с новой схемой + +### Этап 6: Python SDK +Обновить сигнатуру `FlowInstance.embeddings()` +Обновить сигнатуру `SocketFlowInstance.embeddings()` + +## Открытые вопросы + +**Потоковая передача больших пакетов**: Следует ли нам поддерживать потоковую передачу результатов для очень больших пакетов (>100 текстов)? +**Ограничения, специфичные для поставщиков**: Как нам обрабатывать поставщиков с разными максимальными размерами пакетов? +**Обработка частичных сбоев**: Если один текст в пакете завершается сбоем, следует ли нам завершать весь пакет или возвращать частичные результаты? +**Пакетная обработка документов**: Следует ли нам выполнять пакетную обработку по нескольким сообщениям Chunk или сохранять обработку для каждого сообщения? + +## Ссылки + +[Документация FastEmbed](https://github.com/qdrant/fastembed) +[API вложений Ollama](https://github.com/ollama/ollama) +[Реализация сервиса вложений](trustgraph-base/trustgraph/base/embeddings_service.py) +[Оптимизация производительности GraphRAG](graphrag-performance-optimization.md) diff --git a/docs/tech-specs/embeddings-batch-processing.sw.md b/docs/tech-specs/embeddings-batch-processing.sw.md new file mode 100644 index 00000000..3cab53a6 --- /dev/null +++ b/docs/tech-specs/embeddings-batch-processing.sw.md @@ -0,0 +1,667 @@ +# Vipimo vya Kiufundi vya Uendeshaji wa Pamoja wa Matukio (Embeddings) + +## Muhtasari + +Maelekezo haya yanaelezea uboreshaji kwa huduma ya matukio ili kusaidia uendeshaji wa pamoja wa maandishi mengi katika ombi moja. Utaratibu wa sasa huendesha maandishi moja kwa wakati, na hivyo kupoteza faida kubwa za utendaji ambazo modeli za matukio hutoa wakati wa kuendesha matukio. + +1. **Utofauti wa Uendeshaji wa Maandishi Moja**: Utaratibu wa sasa unaficha maandishi ya moja ndani ya orodha, na hivyo kutumia viboresho vya uendeshaji wa FastEmbed. +2. **Mizio ya Ombi kwa Maandishi Kila Moja**: Maandishi kila moja yanahitaji ujumbe tofauti wa Pulsar. +3. **Utofauti wa Uendeshaji wa Modeli**: Modeli za matukio zina gharama thabiti kwa kila kundi; madaraja madogo hutumia rasilimali za GPU/CPU. +4. **Uendeshaji wa Mfululizo katika Huduma Zinazotumia**: Huduma muhimu huenda kupitia vipengele na kuita matukio moja kwa moja. + +## Lengo + +**Usaidizi wa API ya Matukio**: Kuruhusu uendeshaji wa maandishi mengi katika ombi moja. +**Ulinganifu na Mifumo ya Zamani**: Kuendelea kutoa usaidizi kwa ombi la maandishi moja. +**Uboreshaji Mkubwa wa Ufanisi**: Lengo ni uboreshaji wa ufanisi wa mara 5-10 kwa operesheni za jumla. +**Kupunguza Muda wa Kila Maandishi**: Kupunguza muda wa wastani wakati wa kuendesha matukio ya maandishi mengi. +**Ufanisi wa Kumbukumbu**: Kuendesha madaraja bila matumizi mengi ya kumbukumbu. +**Usiohusiana na Mtoa Huduma**: Kusaidia uendeshaji wa pamoja kwa FastEmbed, Ollama, na watoa huduma wengine. +**Kubadilisha Huduma Zinazotumia**: Kusasisha huduma zote zinazotumia matukio ili kutumia API ya matukio ambapo inafaa. + +## Asili + +### Utaratibu wa Sasa - Huduma ya Matukio + +Utaratibu wa matukio katika `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` unaonyesha upotevu mkubwa wa utendaji: + +```python +# fastembed/processor.py line 56 +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + + vecs = self.embeddings.embed([text]) # Single text wrapped in list + + return [v.tolist() for v in vecs] +``` + +**Matatizo:** + +1. **Ukubwa wa Kundi 1**: Njia ya `embed()` ya FastEmbed imeundwa kwa ajili ya usindikaji wa kundi, lakini tunaiita kila wakati na `[text]` - kikundi cha ukubwa wa 1. + +2. **Mizio ya Kila Ombi**: Kila ombi la uainishaji (embedding) hutoa: + Usajili/uondoaji wa ujumbe wa Pulsar + Muda wa kusafiri wa mtandao (latency) + Mizio ya kuanzisha utekelezaji wa mfumo (model inference) + Mizio ya upangaji wa async ya Python + +3. **Kizuia cha Mpango (Schema)**: Mpango wa `EmbeddingsRequest` unaunga mkono tu maandishi moja: + ```python + @dataclass + class EmbeddingsRequest: + text: str = "" # Single text only + ``` + +### Wataalamu Wanaotumia Sasa - Uendeshaji wa Mfululizo + +#### 1. Lango la API + +**Faili:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +Lango linakubali ombi za uingizaji maandishi moja kupitia HTTP/WebSocket na huvipeleka kwa huduma ya uingizaji. Kwa sasa, hakuna mwisho wa kazi za kikundi. + +```python +class EmbeddingsRequestor(ServiceRequestor): + # Handles single EmbeddingsRequest -> EmbeddingsResponse + request_schema=EmbeddingsRequest, # Single text only + response_schema=EmbeddingsResponse, +``` + +**Athari:** Wateja wa nje (programu za wavuti, skripti) lazima wafanye ombi la HTTP N ili kuingiza maandishi N. + +#### 2. Huduma ya Kuingiza Nyaraka + +**Faili:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +Huprosesa vipande vya nyaraka moja kwa moja: + +```python +async def on_message(self, msg, consumer, flow): + v = msg.value() + + # Single chunk per request + resp = await flow("embeddings-request").request( + EmbeddingsRequest(text=v.chunk) + ) + vectors = resp.vectors +``` + +**Athari:** Kila sehemu ya hati inahitaji ombi tofauti la uingizaji (embedding). Hati yenye sehemu 100 = ombi la uingizaji 100. + +#### 3. Huduma ya Uingizaji wa Picha (Graph Embeddings Service) + +**Faili:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + +Inafanya mzunguko kwenye vitu na kuingiza kila kimoja kwa mtiririko: + +```python +async def on_message(self, msg, consumer, flow): + for entity in v.entities: + # Serial embedding - one entity at a time + vectors = await flow("embeddings-request").embed( + text=entity.context + ) + entities.append(EntityEmbeddings( + entity=entity.entity, + vectors=vectors, + chunk_id=entity.chunk_id, + )) +``` + +**Athari:** Ujumbe wenye vitu 50 = ombi la uwekaji wa maandishi (embedding) la kila kitu. Hii ni kikwazo kikubwa wakati wa uundaji wa grafu ya maarifa. + +#### 4. Huduma ya Uwekaji wa Maandishi ya Safu + +**Faili:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + +Huenda kupitia maandishi ya kipekee na huweka kila moja kwa mmoja: + +```python +async def on_message(self, msg, consumer, flow): + for text, (index_name, index_value) in texts_to_embed.items(): + # Serial embedding - one text at a time + vectors = await flow("embeddings-request").embed(text=text) + + embeddings_list.append(RowIndexEmbedding( + index_name=index_name, + index_value=index_value, + text=text, + vectors=vectors + )) +``` + +**Athari:** Kuchakata jedwali lenye maadili 100 ya kipekee yaliyopangwa = maombi 100 ya uwekaji data (embedding) kwa kila moja. + +#### 5. EmbeddingsClient (Mteja wa Msingi) + +**Faili:** `trustgraph-base/trustgraph/base/embeddings_client.py` + +Mteja unaotumika na vichakataji vyote vya mtiririko unao na uwezo wa kuweka data (embedding) kwa maandishi moja tu: + +```python +class EmbeddingsClient(RequestResponse): + async def embed(self, text, timeout=30): + resp = await self.request( + EmbeddingsRequest(text=text), # Single text + timeout=timeout + ) + return resp.vectors +``` + +**Athari:** Wateja wote wanaotumia programu hii wamezuiliwa kufanya kazi za maandishi pekee. + +#### 6. Vifaa vya Amri (Command-Line Tools) + +**Faili:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +Zana ya CLI inakubali hoja moja ya maandishi: + +```python +def query(url, flow_id, text, token=None): + result = flow.embeddings(text=text) # Single text + vectors = result.get("vectors", []) +``` + +**Athari:** Watumiaji hawawezi kuingiza data kwa wingi kupitia amri. Kuchakata faili ya maandishi inahitaji utendaji wa N mara. + +#### 7. SDK ya Python + +SDK ya Python hutoa madarasa mawili ya wateja kwa kuingiliana na huduma za TrustGraph. Zote mbili zinaunga mkono tu kuingiza maandishi moja. + +**Faili:** `trustgraph-base/trustgraph/api/flow.py` + +```python +class FlowInstance: + def embeddings(self, text): + """Get embeddings for a single text""" + input = {"text": text} + return self.request("service/embeddings", input)["vectors"] +``` + +**Faili:** `trustgraph-base/trustgraph/api/socket_client.py` + +```python +class SocketFlowInstance: + def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]: + """Get embeddings for a single text via WebSocket""" + request = {"text": text} + return self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) +``` + +**Athari:** Wasanidi wa Python wanaotumia SDK lazima watumie mzunguko kwenye maandishi na kufanya maombi tofauti ya API. Hakuna msaada wa uingizaji wa data kwa wingi (batch) kwa watumiaji wa SDK. + +### Athari za Utendaji + +Kwa uingizaji wa kawaida wa hati (vifaa 1000 vya maandishi): +**Sasa**: Maombi 1000 tofauti, matumizi 1000 ya mfumo wa utambuzi (model inference). +**Kwa wingi (batch_size=32)**: Maombi 32, matumizi 32 ya mfumo wa utambuzi (96.8% ya kupungua). + +Kwa uingizaji wa data kwa wingi (message na vitu 50): +**Sasa**: Simu 50 za `await` mfululizo, takriban sekunde 5-10. +**Kwa wingi**: Simu 1-2 za wingi, takriban sekunde 0.5-1 (uboreshaji wa mara 5-10). + +Maktaba kama FastEmbed na zile sawa hufikia ongezeko la takriban moja kwa moja la ufanisi kwa wingi, hadi kikomo cha vifaa (kawaida vifaa 32-128 kwa wingi). + +## Muundo wa Kiufundi + +### Muundo + +Uboreshaji wa uingizaji wa data kwa wingi unahitaji mabadiliko katika vipengele vifuatavyo: + +#### 1. **Uboreshaji wa Mfumo** + Panua `EmbeddingsRequest` ili kusaidia maandishi mengi. + Panua `EmbeddingsResponse` ili kurejesha seti nyingi za vector. + Dumishe utangamano na maombi ya maandishi moja. + + Moduli: `trustgraph-base/trustgraph/schema/services/llm.py` + +#### 2. **Uboreshaji wa Huduma ya Msingi** + Sasisha `EmbeddingsService` ili kushughulikia maombi ya wingi. + Ongeza usanidi wa ukubwa wa wingi. + Lenga ushughulikiaji wa maombi unaoelinganisha na wingi. + + Moduli: `trustgraph-base/trustgraph/base/embeddings_service.py` + +#### 3. **Sasisho za Mchakato wa Mtoa Huduma** + Sasisha mchakato wa FastEmbed ili kupitisha wingi kamili kwa `embed()`. + Sasisha mchakato wa Ollama ili kushughulikia wingi (ikiwa inasaidiwa). + Ongeza ushughulikiaji wa mfululizo kama njia ya dharura kwa watoa huduma ambao hawasaidii wingi. + + Moduli: + `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` + `trustgraph-flow/trustgraph/embeddings/ollama/processor.py` + +#### 4. **Uboreshaji kwa Mteja** + Ongeza njia ya kuingiza data kwa wingi katika `EmbeddingsClient` + Saidia API za moja kwa moja na za wingi + Ongeza uingizaji wa data kwa wingi kwa data kubwa + + Moduli: `trustgraph-base/trustgraph/base/embeddings_client.py` + +#### 5. **Sasisho kwa Msimuizi - Wasindikaji wa Mchakato** + Sasisha `graph_embeddings` ili kuingiza muktadha wa vitu kwa wingi + Sasisha `row_embeddings` ili kuingiza maandishi ya faharasa kwa wingi + Sasisha `document_embeddings` ikiwa uingizaji wa data kwa wingi unawezekana + + Moduli: + `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +#### 6. **Uboreshaji kwa Lango la API** + Ongeza mwisho wa kuingiza data kwa wingi + Saidia safu ya maandishi katika mwili wa ombi + + Moduli: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +#### 7. **Uboreshaji kwa Zana ya CLI** + Ongeza usaidizi wa maandishi mengi au uingizaji wa faili + Ongeza parameter ya ukubwa wa wingi + + Moduli: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +#### 8. **Uboreshaji kwa SDK ya Python** + Ongeza njia ya `embeddings_batch()` katika `FlowInstance` + Ongeza njia ya `embeddings_batch()` katika `SocketFlowInstance` + Saidia API za moja kwa moja na za wingi kwa watumiaji wa SDK + + Moduli: + `trustgraph-base/trustgraph/api/flow.py` + `trustgraph-base/trustgraph/api/socket_client.py` + +### Mifano ya Data + +#### EmbeddingsRequest + +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +Matumizi: +Nakala moja: `EmbeddingsRequest(texts=["hello world"])` +Kundi: `EmbeddingsRequest(texts=["text1", "text2", "text3"])` + +#### Jibu la Uelekezaji + +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +Muundo wa majibu: +`vectors[i]` ina mkusanyiko wa vektali kwa `texts[i]` +Kila mkusanyiko wa vektali ni `list[list[float]]` (modeli zinaweza kurejesha vektali nyingi kwa kila maandishi) +Kwa mfano: maandishi 3 → `vectors` ina vipengele 3, kila kipengele kina uelekezo wa maandishi hayo + +### API + +#### EmbeddingsClient + +```python +class EmbeddingsClient(RequestResponse): + async def embed( + self, + texts: list[str], + timeout: float = 300, + ) -> list[list[list[float]]]: + """ + Embed one or more texts in a single request. + + Args: + texts: List of texts to embed + timeout: Timeout for the operation + + Returns: + List of vector sets, one per input text + """ + resp = await self.request( + EmbeddingsRequest(texts=texts), + timeout=timeout + ) + if resp.error: + raise RuntimeError(resp.error.message) + return resp.vectors +``` + +#### Ncha ya Ufikiaji (Endpoint) ya Uingizaji (Embedding) ya Langara ya API + +Ncha ya ufikiaji (endpoint) imesasishwa ili kusaidia uingizaji (embedding) mmoja au wa kikundi: + +``` +POST /api/v1/embeddings +Content-Type: application/json + +{ + "texts": ["text1", "text2", "text3"], + "flow_id": "default" +} + +Response: +{ + "vectors": [ + [[0.1, 0.2, ...]], + [[0.3, 0.4, ...]], + [[0.5, 0.6, ...]] + ] +} +``` + +### Maelezo ya Utendaji + +#### Awamu ya 1: Marekebisho ya Mfumo + +**Ombi la Uingizaji:** +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +**Jibu la Uingizwaji:** +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +**Sasisho la `EmbeddingsService.on_request`:** +```python +async def on_request(self, msg, consumer, flow): + request = msg.value() + id = msg.properties()["id"] + model = flow("model") + + vectors = await self.on_embeddings(request.texts, model=model) + response = EmbeddingsResponse(error=None, vectors=vectors) + + await flow("response").send(response, properties={"id": id}) +``` + +#### Awamu ya 2: Sasisho la Mchakato wa FastEmbed + +**Sasa (Haina ufanisi):** +```python +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + vecs = self.embeddings.embed([text]) # Batch of 1 + return [v.tolist() for v in vecs] +``` + +**Imebhadiliwa:** +```python +async def on_embeddings(self, texts: list[str], model=None): + """Embed texts - processes all texts in single model call""" + if not texts: + return [] + + use_model = model or self.default_model + self._load_model(use_model) + + # FastEmbed handles the full batch efficiently + all_vecs = list(self.embeddings.embed(texts)) + + # Return list of vector sets, one per input text + return [[v.tolist()] for v in all_vecs] +``` + +#### Awamu ya 3: Sasisho la Huduma ya Uingizaji Picha kwenye Grafu + +**Sasa (Mfululizo):** +```python +async def on_message(self, msg, consumer, flow): + entities = [] + for entity in v.entities: + vectors = await flow("embeddings-request").embed(text=entity.context) + entities.append(EntityEmbeddings(...)) +``` + +**Imebhadilishwa (Kundi):** +```python +async def on_message(self, msg, consumer, flow): + # Collect all contexts + contexts = [entity.context for entity in v.entities] + + # Single batch embedding call + all_vectors = await flow("embeddings-request").embed(texts=contexts) + + # Pair results with entities + entities = [ + EntityEmbeddings( + entity=entity.entity, + vectors=vectors[0], # First vector from the set + chunk_id=entity.chunk_id, + ) + for entity, vectors in zip(v.entities, all_vectors) + ] +``` + +#### Awamu ya 4: Sasisho la Huduma ya Uwekaji Data katika Safu + +**Sasa (Mfululizo):** +```python +for text, (index_name, index_value) in texts_to_embed.items(): + vectors = await flow("embeddings-request").embed(text=text) + embeddings_list.append(RowIndexEmbedding(...)) +``` + +**Imebhadilishwa (Kundi):** +```python +# Collect texts and metadata +texts = list(texts_to_embed.keys()) +metadata = list(texts_to_embed.values()) + +# Single batch embedding call +all_vectors = await flow("embeddings-request").embed(texts=texts) + +# Pair results +embeddings_list = [ + RowIndexEmbedding( + index_name=meta[0], + index_value=meta[1], + text=text, + vectors=vectors[0] # First vector from the set + ) + for text, meta, vectors in zip(texts, metadata, all_vectors) +] +``` + +#### Awamu ya 5: Kuboresha Zana ya Kifaa cha Amri (CLI) + +**CLI iliyoboreshwa:** +```python +def main(): + parser = argparse.ArgumentParser(...) + + parser.add_argument( + 'text', + nargs='*', # Zero or more texts + help='Text(s) to convert to embedding vectors', + ) + + parser.add_argument( + '-f', '--file', + help='File containing texts (one per line)', + ) + + parser.add_argument( + '--batch-size', + type=int, + default=32, + help='Batch size for processing (default: 32)', + ) +``` + +Matumizi: +```bash +# Single text (existing) +tg-invoke-embeddings "hello world" + +# Multiple texts +tg-invoke-embeddings "text one" "text two" "text three" + +# From file +tg-invoke-embeddings -f texts.txt --batch-size 64 +``` + +#### Awamu ya 6: Kuboresha Kitengo cha Programu (SDK) cha Python + +**FlowInstance (mfumo wa wateja wa HTTP):** + +```python +class FlowInstance: + def embeddings(self, texts: list[str]) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + input = {"texts": texts} + return self.request("service/embeddings", input)["vectors"] +``` + +**SocketFlowInstance (mfumo wa mteja wa WebSocket):** + +```python +class SocketFlowInstance: + def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts via WebSocket. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + request = {"texts": texts} + response = self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) + return response["vectors"] +``` + +**Mfano wa Matumizi ya SDK:** + +```python +# Single text +vectors = flow.embeddings(["hello world"]) +print(f"Dimensions: {len(vectors[0][0])}") + +# Batch embedding +texts = ["text one", "text two", "text three"] +all_vectors = flow.embeddings(texts) + +# Process results +for text, vecs in zip(texts, all_vectors): + print(f"{text}: {len(vecs[0])} dimensions") +``` + +## Mambo ya Kuzingatia Kuhusu Usalama + +**Vikomo vya Ukubwa wa Ombi**: Punguza ukubwa wa juu wa kila kikundi ili kuzuia matumizi yasiyofaa ya rasilimali. +**Usimamizi wa Muda wa Hesabu (Timeout)**: Punguza muda wa hesabu ipasavyo kwa ukubwa wa kikundi. +**Vikomo vya Kumbukumbu**: Fuatilia matumizi ya kumbukumbu kwa vikundi vikubwa. +**Uthibitisho wa Pembejeo**: Thibitisha maandishi yote katika kikundi kabla ya kuchakata. + +## Mambo ya Kuzingatia Kuhusu Utendaji + +### Ubora Unaotarajiwa + +**Uwezo wa Kuchakata (Throughput):** +Maandishi moja: ~10-50 maandishi/sekunde (kulingana na mfumo) +Kikundi (ukubwa wa 32): ~200-500 maandishi/sekunde (uboreshaji wa 5-10x) + +**Muda wa Kuchakata Kila Maandishi:** +Maandishi moja: 50-200ms kwa kila maandishi +Kikundi (ukubwa wa 32): 5-20ms kwa kila maandishi (kwa wastani) + +**Ubora Maalum kwa Huduma:** + +| Huduma | Sasa | Kwa Kikundi | Uboreshaji | +|---------|---------|---------|-------------| +| Uwekaji Picha (50 vitu) | 5-10s | 0.5-1s | 5-10x | +| Uwekaji Mistari (100 maandishi) | 10-20s | 1-2s | 5-10x | +| Uingizaji wa Hati (1000 sehemu) | 100-200s | 10-30s | 5-10x | + +### Vigezo vya Usanidi + +```python +# Recommended defaults +DEFAULT_BATCH_SIZE = 32 +MAX_BATCH_SIZE = 128 +BATCH_TIMEOUT_MULTIPLIER = 2.0 +``` + +## Mbinu ya Majaribio + +### Majaribio ya Kitengo +Uingizaji wa maandishi moja (utangamano wa nyuma) +Usimamizi wa kundi tupu +Utumiaji wa ukubwa wa juu wa kundi +Usimamizi wa makosa kwa kushindwa kwa kundi + +### Majaribio ya Uunganisho +Uingizaji wa kundi kamili kupitia Pulsar +Uchakataji wa kundi wa huduma ya uingizaji wa grafu +Uchakataji wa kundi wa huduma ya uingizaji wa mstari +Ncha ya kundi ya lango la API + +### Majaribio ya Utendaji +Tathmini ya kasi ya uingizaji wa moja dhidi ya kundi +Matumizi ya kumbukumbu chini ya saizi tofauti za kundi +Uchambuzi wa usambazaji wa kuchelewesha + +## Mpango wa Uhamisho + +Hii ni toleo la mabadiliko makubwa. Awamu zote zinafanywa pamoja. + +### Awamu ya 1: Mabadiliko ya Mpango +Badilisha `text: str` na `texts: list[str]` katika EmbeddingsRequest +Badilisha aina ya `vectors` kuwa `list[list[list[float]]]` katika EmbeddingsResponse + +### Awamu ya 2: Masuala ya Marekebisho +Sasisha saini ya `on_embeddings` katika washauri wa FastEmbed na Ollama +Chakata kundi kamili katika wito mmoja wa modeli + +### Awamu ya 3: Masuala ya Wateja +Sasisha `EmbeddingsClient.embed()` ili kukubali `texts: list[str]` + +### Awamu ya 4: Watumiaji +Sasisha graph_embeddings ili kuingiza muktadha wa vitu katika kundi +Sasisha row_embeddings ili kuingiza maandishi ya faharasa katika kundi +Sasisha document_embeddings ili itumie mpango mpya +Sasisha zana ya CLI + +### Awamu ya 5: Lango la API +Sasisha ncha ya uingizaji kwa mpango mpya + +### Awamu ya 6: SDK ya Python +Sasisha saini ya `FlowInstance.embeddings()` +Sasisha saini ya `SocketFlowInstance.embeddings()` + +## Maswali ya Funguo + +**Uingizaji wa Kundi Kubwa**: Je, tunapaswa kusaidia uingizaji wa matokeo kwa kundi kubwa sana (>100 maandishi)? +**Vikomo Maalum vya Mtoa Huduma**: Je, tunapaswa kushughulikia watoa huduma wenye saizi tofauti za kundi? +**Usimamizi wa Kushindwa kwa Kiasi**: Ikiwa maandishi moja katika kundi kushindwa, je, tunapaswa kushindwa kundi lote au kurudisha matokeo ya sehemu? +**Uingizaji wa Kundi wa Mengine**: Je, tunapaswa kuingiza kote kwa ujumbe mwingi wa Chunk au kuendelea na uchakataji wa kila ujumbe? + +## Marejeleo + +[Dokumenti ya FastEmbed](https://github.com/qdrant/fastembed) +[API ya Uingizaji ya Ollama](https://github.com/ollama/ollama) +[Utekelezaji wa Huduma ya Uingizaji](trustgraph-base/trustgraph/base/embeddings_service.py) +[Uboreshaji wa Utendaji wa GraphRAG](graphrag-performance-optimization.md) diff --git a/docs/tech-specs/embeddings-batch-processing.tr.md b/docs/tech-specs/embeddings-batch-processing.tr.md new file mode 100644 index 00000000..228fc017 --- /dev/null +++ b/docs/tech-specs/embeddings-batch-processing.tr.md @@ -0,0 +1,667 @@ +# Gömme İşlemleri Toplu İşleme Teknik Özellikleri + +## Genel Bakış + +Bu teknik özellik, gömme hizmeti için, tek bir istekte birden fazla metni toplu olarak işleyebilmeyi desteklemek amacıyla yapılan optimizasyonları açıklamaktadır. Mevcut uygulama, her seferinde tek bir metni işlemektedir ve bu durum, gömme modellerinin toplu işlemler sırasında sağladığı önemli performans avantajlarından yararlanılmamasına neden olmaktadır. + +1. **Tek Metin İşleme Verimsizliği**: Mevcut uygulama, tek metinleri bir liste içinde kullanarak, FastEmbed'in toplu işleme yeteneklerini tam olarak kullanamamaktadır. +2. **Metin Başına İstek Yükü**: Her metin için ayrı bir Pulsar mesajı gönderilip alınması gerekmektedir. +3. **Model Çıkarım Verimsizliği**: Gömme modellerinin sabit bir toplu işleme yükü vardır; küçük toplu işlemler GPU/CPU kaynaklarının israfına yol açar. +4. **Çağıran Tarafında Seri İşleme**: Önemli hizmetler, öğeler üzerinde döngü yaparak gömme işlemlerini tek tek gerçekleştirmektedir. + +## Hedefler + +**Toplu API Desteği**: Tek bir istekte birden fazla metni işleyebilmeyi destekleyin. +**Geriye Dönük Uyumluluk**: Tek metin isteklerine olan desteği koruyun. +**Önemli Verimlilik Artışı**: Toplu işlemler için 5-10 kat verimlilik artışı hedefleyin. +**Metin Başına Azaltılmış Gecikme**: Birden fazla metni gömme işlemi sırasında amortize gecikmeyi azaltın. +**Bellek Verimliliği**: Aşırı bellek tüketimi olmadan toplu işlemleri gerçekleştirin. +**Sağlayıcıdan Bağımsızlık**: FastEmbed, Ollama ve diğer sağlayıcılar arasında toplu işleme desteğini sağlayın. +**Çağıran Taraf Güncellemesi**: Toplu API'nin faydalı olduğu durumlarda tüm gömme işlemlerini kullanan hizmetleri güncelleyin. + +## Arka Plan + +### Mevcut Uygulama - Gömme Hizmeti + +`trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` içindeki gömme uygulamasında önemli bir performans verimsizliği bulunmaktadır: + +```python +# fastembed/processor.py line 56 +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + + vecs = self.embeddings.embed([text]) # Single text wrapped in list + + return [v.tolist() for v in vecs] +``` + +**Sorunlar:** + +1. **Batch Boyutu 1:** FastEmbed'in `embed()` yöntemi, toplu işleme için optimize edilmiştir, ancak bunu her zaman `[text]` - 1 boyutlu bir toplu işleme ile çağırıyoruz. + +2. **İstek Başına Ek Yük:** Her gömme isteği aşağıdaki ek yükleri içerir: + Pulsar mesajı serileştirme/deserileştirme + Ağ gidiş-dönüş gecikmesi + Model çıkarım başlatma ek yükü + Python asenkron planlama ek yükü + +3. **Şema Sınırlaması:** `EmbeddingsRequest` şeması yalnızca tek bir metni destekler: + ```python + @dataclass + class EmbeddingsRequest: + text: str = "" # Single text only + ``` + +### Mevcut Çağrılar - Seri İşleme + +#### 1. API Ağ Geçidi + +**Dosya:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +Ağ geçidi, HTTP/WebSocket üzerinden tek metin gömme isteklerini kabul eder ve bunları gömme hizmetine yönlendirir. Şu anda toplu işlem için bir uç nokta bulunmamaktadır. + +```python +class EmbeddingsRequestor(ServiceRequestor): + # Handles single EmbeddingsRequest -> EmbeddingsResponse + request_schema=EmbeddingsRequest, # Single text only + response_schema=EmbeddingsResponse, +``` + +**Etki:** Harici müşteriler (web uygulamaları, betikler), N metni yerleştirmek için N adet HTTP isteği yapmalıdır. + +#### 2. Belge Gömme Hizmeti + +**Dosya:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +Belgeleri tek tek parçalar halinde işler: + +```python +async def on_message(self, msg, consumer, flow): + v = msg.value() + + # Single chunk per request + resp = await flow("embeddings-request").request( + EmbeddingsRequest(text=v.chunk) + ) + vectors = resp.vectors +``` + +**Etki:** Her belge parçası için ayrı bir gömme (embedding) çağrısı gereklidir. 100 parçadan oluşan bir belge = 100 gömme isteği. + +#### 3. Grafik Gömme Hizmeti + +**Dosya:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + +Varlıklar üzerinde döngü yapar ve her birini sırayla gömer: + +```python +async def on_message(self, msg, consumer, flow): + for entity in v.entities: + # Serial embedding - one entity at a time + vectors = await flow("embeddings-request").embed( + text=entity.context + ) + entities.append(EntityEmbeddings( + entity=entity.entity, + vectors=vectors, + chunk_id=entity.chunk_id, + )) +``` + +**Etki:** 50 varlık içeren bir mesaj, 50 adet ardışık gömme (embedding) isteği anlamına gelir. Bu, bilgi grafiği oluşturma sırasında büyük bir darboğazdır. + +#### 4. Satır Gömme Hizmeti + +**Dosya:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + +Benzersiz metinler üzerinde döngü yapar ve her birini sırayla gömer: + +```python +async def on_message(self, msg, consumer, flow): + for text, (index_name, index_value) in texts_to_embed.items(): + # Serial embedding - one text at a time + vectors = await flow("embeddings-request").embed(text=text) + + embeddings_list.append(RowIndexEmbedding( + index_name=index_name, + index_value=index_value, + text=text, + vectors=vectors + )) +``` + +**Etki:** 100 benzersiz indeksli değere sahip bir tabloyu işlemek = 100 ardışık gömme isteği. + +#### 5. EmbeddingsClient (Temel İstemci) + +**Dosya:** `trustgraph-base/trustgraph/base/embeddings_client.py` + +Tüm iş akışı işleyicileri tarafından kullanılan istemci, yalnızca tek metin gömmesini destekler: + +```python +class EmbeddingsClient(RequestResponse): + async def embed(self, text, timeout=30): + resp = await self.request( + EmbeddingsRequest(text=text), # Single text + timeout=timeout + ) + return resp.vectors +``` + +**Etki:** Bu istemciyi kullanan tüm uygulamalar, yalnızca tek metin işlemleriyle sınırlıdır. + +#### 6. Komut Satırı Araçları + +**Dosya:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +CLI aracı, tek bir metin argümanı alır: + +```python +def query(url, flow_id, text, token=None): + result = flow.embeddings(text=text) # Single text + vectors = result.get("vectors", []) +``` + +**Etki:** Kullanıcılar, komut satırından toplu gömme işlemi yapamaz. Bir metin dosyasını işlemek, N sayıda çağrı gerektirir. + +#### 7. Python SDK + +Python SDK, TrustGraph hizmetleriyle etkileşim kurmak için iki istemci sınıfı sağlar. Her ikisi de yalnızca tek metin gömme işlemini destekler. + +**Dosya:** `trustgraph-base/trustgraph/api/flow.py` + +```python +class FlowInstance: + def embeddings(self, text): + """Get embeddings for a single text""" + input = {"text": text} + return self.request("service/embeddings", input)["vectors"] +``` + +**Dosya:** `trustgraph-base/trustgraph/api/socket_client.py` + +```python +class SocketFlowInstance: + def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]: + """Get embeddings for a single text via WebSocket""" + request = {"text": text} + return self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) +``` + +**Etki:** SDK'yı kullanan Python geliştiricilerinin, metinler üzerinde döngü yapması ve N adet API çağrısı yapması gerekir. SDK kullanıcıları için toplu gömme desteği mevcut değildir. + +### Performans Etkisi + +Tipik belge yükleme için (1000 metin parçası): +**Mevcut:** 1000 ayrı istek, 1000 model çıkarım çağrısı +**Toplu (batch_size=32):** 32 istek, 32 model çıkarım çağrısı (%96,8 azalma) + +Grafik gömme için (50 varlığa sahip mesaj): +**Mevcut:** 50 ardışık bekletme çağrısı, ~5-10 saniye +**Toplu:** 1-2 toplu çağrı, ~0,5-1 saniye (5-10 kat iyileşme) + +FastEmbed ve benzeri kütüphaneler, toplu boyutun donanım sınırlarına kadar ulaştığı durumlarda, yaklaşık doğrusal bir verim ölçeklemesi sağlar (tipik olarak toplu boyutta 32-128 metin). + +## Teknik Tasarım + +### Mimari + +Gömme toplu işleme optimizasyonu, aşağıdaki bileşenlerde değişiklikler gerektirir: + +#### 1. **Şema Geliştirme** + `EmbeddingsRequest`'ı, birden fazla metni destekleyecek şekilde genişletin + `EmbeddingsResponse`'ı, birden fazla vektör kümesini döndürecek şekilde genişletin + Tek metin istekleriyle uyumluluğu koruyun + + Modül: `trustgraph-base/trustgraph/schema/services/llm.py` + +#### 2. **Temel Servis Geliştirme** + `EmbeddingsService`'ı, toplu istekleri işleyebilecek şekilde güncelleyin + Toplu boyut yapılandırması ekleyin + Toplu işleme duyarlı istek işleme uygulayın + + Modül: `trustgraph-base/trustgraph/base/embeddings_service.py` + +#### 3. **Sağlayıcı İşlemcisi Güncellemeleri** + FastEmbed işlemcisini güncelleyin, böylece tam toplu iş yükünü `embed()`'a iletebilir + Ollama işlemcisini güncelleyin, böylece toplu işlemleri işleyebilir (destekleniyorsa) + Toplu işlemeyi desteklemeyen sağlayıcılar için yedek sıralı işlemeyi ekleyin + + Modüller: + `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` + `trustgraph-flow/trustgraph/embeddings/ollama/processor.py` + +#### 4. **İstemci Geliştirme** + `EmbeddingsClient`'a toplu gömme yöntemini ekleyin + Hem tek hem de toplu API'leri destekleyin + Büyük girdiler için otomatik toplu işlemeyi ekleyin + + Modül: `trustgraph-base/trustgraph/base/embeddings_client.py` + +#### 5. **Çağrı Güncellemeleri - Akış İşlemcileri** + `graph_embeddings`'ı, varlık bağlamlarını toplu hale getirecek şekilde güncelleyin + `row_embeddings`'ı, indeks metinlerini toplu hale getirecek şekilde güncelleyin + Mesaj toplu işlemesi mümkünse, `document_embeddings`'ı güncelleyin + + Modüller: + `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +#### 6. **API Ağ Geçidi Geliştirme** + Toplu gömme uç noktası ekleyin + İstek gövdesinde metin dizisini destekleyin + + Modül: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +#### 7. **CLI Aracı Geliştirme** + Birden fazla metin veya dosya girişi desteği ekleyin + Toplu boyut parametresi ekleyin + + Modül: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +#### 8. **Python SDK Geliştirme** + `embeddings_batch()` yöntemini `FlowInstance`'e ekleyin + `embeddings_batch()` yöntemini `SocketFlowInstance`'e ekleyin + SDK kullanıcıları için hem tek hem de toplu API'leri destekleyin + + Modüller: + `trustgraph-base/trustgraph/api/flow.py` + `trustgraph-base/trustgraph/api/socket_client.py` + +### Veri Modelleri + +#### EmbeddingsRequest + +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +Kullanım: +Tek metin: `EmbeddingsRequest(texts=["hello world"])` +Toplu işlem: `EmbeddingsRequest(texts=["text1", "text2", "text3"])` + +#### EmbeddingsResponse + +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +Yanıt yapısı: +`vectors[i]`, `texts[i]` için vektör kümesini içerir. +Her vektör kümesi `list[list[float]]`'dır (modeller, her metin için birden fazla vektör döndürebilir). +Örnek: 3 metin → `vectors`, 3 giriş içerir ve her giriş, o metnin gömülme değerlerini içerir. + +### API'ler + +#### EmbeddingsClient + +```python +class EmbeddingsClient(RequestResponse): + async def embed( + self, + texts: list[str], + timeout: float = 300, + ) -> list[list[list[float]]]: + """ + Embed one or more texts in a single request. + + Args: + texts: List of texts to embed + timeout: Timeout for the operation + + Returns: + List of vector sets, one per input text + """ + resp = await self.request( + EmbeddingsRequest(texts=texts), + timeout=timeout + ) + if resp.error: + raise RuntimeError(resp.error.message) + return resp.vectors +``` + +#### API Gateway Gömülü Veri (Embeddings) Uç Noktası + +Tek bir veya toplu gömülü veri desteğini sağlayan güncellenmiş uç nokta: + +``` +POST /api/v1/embeddings +Content-Type: application/json + +{ + "texts": ["text1", "text2", "text3"], + "flow_id": "default" +} + +Response: +{ + "vectors": [ + [[0.1, 0.2, ...]], + [[0.3, 0.4, ...]], + [[0.5, 0.6, ...]] + ] +} +``` + +### Uygulama Detayları + +#### Aşama 1: Şema Değişiklikleri + +**EmbeddingsRequest:** +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +**Gömme Yanıtı:** +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +**Güncellenmiş EmbeddingsService.on_request:** +```python +async def on_request(self, msg, consumer, flow): + request = msg.value() + id = msg.properties()["id"] + model = flow("model") + + vectors = await self.on_embeddings(request.texts, model=model) + response = EmbeddingsResponse(error=None, vectors=vectors) + + await flow("response").send(response, properties={"id": id}) +``` + +#### 2. Aşama: FastEmbed İşlemci Güncellemesi + +**Mevcut (Verimsiz):** +```python +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + vecs = self.embeddings.embed([text]) # Batch of 1 + return [v.tolist() for v in vecs] +``` + +**Güncellendi:** +```python +async def on_embeddings(self, texts: list[str], model=None): + """Embed texts - processes all texts in single model call""" + if not texts: + return [] + + use_model = model or self.default_model + self._load_model(use_model) + + # FastEmbed handles the full batch efficiently + all_vecs = list(self.embeddings.embed(texts)) + + # Return list of vector sets, one per input text + return [[v.tolist()] for v in all_vecs] +``` + +#### 3. Aşama: Grafik Gömme Hizmeti Güncellemesi + +**Mevcut (Sıralı):** +```python +async def on_message(self, msg, consumer, flow): + entities = [] + for entity in v.entities: + vectors = await flow("embeddings-request").embed(text=entity.context) + entities.append(EntityEmbeddings(...)) +``` + +**Güncellendi (Toplu İşlem):** +```python +async def on_message(self, msg, consumer, flow): + # Collect all contexts + contexts = [entity.context for entity in v.entities] + + # Single batch embedding call + all_vectors = await flow("embeddings-request").embed(texts=contexts) + + # Pair results with entities + entities = [ + EntityEmbeddings( + entity=entity.entity, + vectors=vectors[0], # First vector from the set + chunk_id=entity.chunk_id, + ) + for entity, vectors in zip(v.entities, all_vectors) + ] +``` + +#### 4. Aşama: Satır Gömme Hizmeti Güncellemesi + +**Mevcut (Sıralı):** +```python +for text, (index_name, index_value) in texts_to_embed.items(): + vectors = await flow("embeddings-request").embed(text=text) + embeddings_list.append(RowIndexEmbedding(...)) +``` + +**Güncellendi (Toplu İşlem):** +```python +# Collect texts and metadata +texts = list(texts_to_embed.keys()) +metadata = list(texts_to_embed.values()) + +# Single batch embedding call +all_vectors = await flow("embeddings-request").embed(texts=texts) + +# Pair results +embeddings_list = [ + RowIndexEmbedding( + index_name=meta[0], + index_value=meta[1], + text=text, + vectors=vectors[0] # First vector from the set + ) + for text, meta, vectors in zip(texts, metadata, all_vectors) +] +``` + +#### 5. Aşama: Komut Satırı Arama Aracı Geliştirme + +**Güncellenmiş Komut Satırı:** +```python +def main(): + parser = argparse.ArgumentParser(...) + + parser.add_argument( + 'text', + nargs='*', # Zero or more texts + help='Text(s) to convert to embedding vectors', + ) + + parser.add_argument( + '-f', '--file', + help='File containing texts (one per line)', + ) + + parser.add_argument( + '--batch-size', + type=int, + default=32, + help='Batch size for processing (default: 32)', + ) +``` + +Kullanım: +```bash +# Single text (existing) +tg-invoke-embeddings "hello world" + +# Multiple texts +tg-invoke-embeddings "text one" "text two" "text three" + +# From file +tg-invoke-embeddings -f texts.txt --batch-size 64 +``` + +#### 6. Aşama: Python SDK Geliştirme + +**FlowInstance (HTTP istemcisi):** + +```python +class FlowInstance: + def embeddings(self, texts: list[str]) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + input = {"texts": texts} + return self.request("service/embeddings", input)["vectors"] +``` + +**SocketFlowInstance (WebSocket istemcisi):** + +```python +class SocketFlowInstance: + def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts via WebSocket. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + request = {"texts": texts} + response = self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) + return response["vectors"] +``` + +**SDK Kullanım Örnekleri:** + +```python +# Single text +vectors = flow.embeddings(["hello world"]) +print(f"Dimensions: {len(vectors[0][0])}") + +# Batch embedding +texts = ["text one", "text two", "text three"] +all_vectors = flow.embeddings(texts) + +# Process results +for text, vecs in zip(texts, all_vectors): + print(f"{text}: {len(vecs[0])} dimensions") +``` + +## Güvenlik Hususları + +**İstek Boyutu Sınırları**: Kaynak tükenmesini önlemek için maksimum toplu işlem boyutunu zorlayın. +**Zaman Aşımı İşleme**: Toplu işlem boyutu için zaman aşımını uygun şekilde ayarlayın. +**Bellek Sınırları**: Büyük toplu işlemler için bellek kullanımını izleyin. +**Giriş Doğrulama**: İşleme yapmadan önce toplu işlemdeki tüm metinleri doğrulayın. + +## Performans Hususları + +### Beklenen İyileştirmeler + +**Verim:** +Tek metin: ~10-50 metin/saniye (modele bağlı olarak) +Toplu işlem (boyut 32): ~200-500 metin/saniye (5-10 kat iyileşme) + +**Metin Başına Gecikme:** +Tek metin: metin başına 50-200 ms +Toplu işlem (boyut 32): metin başına 5-20 ms (ortalama) + +**Hizmete Özel İyileştirmeler:** + +| Hizmet | Mevcut | Toplu | İyileşme | +|---------|---------|---------|-------------| +| Grafik Gömme (50 varlık) | 5-10 saniye | 0,5-1 saniye | 5-10 kat | +| Satır Gömme (100 metin) | 10-20 saniye | 1-2 saniye | 5-10 kat | +| Belge Alma (1000 parça) | 100-200 saniye | 10-30 saniye | 5-10 kat | + +### Yapılandırma Parametreleri + +```python +# Recommended defaults +DEFAULT_BATCH_SIZE = 32 +MAX_BATCH_SIZE = 128 +BATCH_TIMEOUT_MULTIPLIER = 2.0 +``` + +## Test Stratejisi + +### Birim Testleri +Tek metin gömülmesi (geriye dönük uyumluluk) +Boş toplu iş işleme +Maksimum toplu iş boyutu zorlaması +Kısmi toplu iş hataları için hata işleme + +### Entegrasyon Testleri +Pulsar üzerinden uçtan uca toplu iş gömülmesi +Grafik gömme hizmeti toplu iş işleme +Satır gömme hizmeti toplu iş işleme +API ağ geçidi toplu iş uç noktası + +### Performans Testleri +Tek ve toplu iş verimini karşılaştırma +Farklı toplu iş boyutları altındaki bellek kullanımı +Gecikme dağılımı analizi + +## Geçiş Planı + +Bu, önemli değişikliklere neden olan bir sürümdür. Tüm fazlar birlikte uygulanır. + +### 1. Aşama: Şema Değişiklikleri +EmbeddingsRequest'teki `text: str`'ı `texts: list[str]` ile değiştirin +EmbeddingsResponse'taki `vectors` türünü `list[list[list[float]]]` olarak değiştirin + +### 2. Aşama: İşlemci Güncellemeleri +FastEmbed ve Ollama işlemcilerindeki `on_embeddings` imzasını güncelleyin +Tam toplu işi tek bir model çağrısında işleyin + +### 3. Aşama: İstemci Güncellemeleri +`EmbeddingsClient.embed()`'ı `texts: list[str]`'i kabul edecek şekilde güncelleyin + +### 4. Aşama: Çağıran Güncellemeleri +graph_embeddings'i toplu iş varlık bağlamlarını kullanacak şekilde güncelleyin +row_embeddings'i toplu iş indeks metinlerini kullanacak şekilde güncelleyin +document_embeddings'i yeni şemayı kullanacak şekilde güncelleyin +CLI aracını güncelleyin + +### 5. Aşama: API Ağ Geçidi +Yeni şema için gömme uç noktasını güncelleyin + +### 6. Aşama: Python SDK +`FlowInstance.embeddings()` imzasını güncelleyin +`SocketFlowInstance.embeddings()` imzasını güncelleyin + +## Açık Sorular + +**Büyük Toplu İşlerin Akışı**: Çok büyük toplu işler (>100 metin) için sonuçları akış olarak desteklemeli miyiz? +**Sağlayıcıya Özel Sınırlar**: Farklı maksimum toplu iş boyutlarına sahip sağlayıcıları nasıl ele almalıyız? +**Kısmi Hata İşleme**: Bir toplu işteki bir metin başarısız olursa, tüm toplu işi mi başarısız etmeliyiz yoksa kısmi sonuçları mı döndürmeliyiz? +**Belge Gömme Toplu İşleme**: Çoklu Chunk mesajları arasında toplu işlemeyi mi yapmalıyız yoksa her mesaj için ayrı ayrı işlemeyi mi korumalıyız? + +## Referanslar + +[FastEmbed Belgeleri](https://github.com/qdrant/fastembed) +[Ollama Gömme API'si](https://github.com/ollama/ollama) +[EmbeddingsService Uygulaması](trustgraph-base/trustgraph/base/embeddings_service.py) +[GraphRAG Performans Optimizasyonu](graphrag-performance-optimization.md) diff --git a/docs/tech-specs/embeddings-batch-processing.zh-cn.md b/docs/tech-specs/embeddings-batch-processing.zh-cn.md new file mode 100644 index 00000000..84fb0d65 --- /dev/null +++ b/docs/tech-specs/embeddings-batch-processing.zh-cn.md @@ -0,0 +1,667 @@ +# 嵌入式批量处理技术规范 + +## 概述 + +本规范描述了对嵌入式服务的优化,以支持在单个请求中批量处理多个文本。当前的实现方式一次处理一个文本,而没有利用嵌入式模型在处理批量数据时所能提供的显著性能优势。 + +1. **单文本处理效率低下**: 当前实现将单个文本包装在列表中,没有充分利用 FastEmbed 的批量处理能力。 +2. **每个文本的请求开销**: 每个文本都需要单独的 Pulsar 消息往返。 +3. **模型推理效率低下**: 嵌入式模型具有固定的批量处理开销;小批量会浪费 GPU/CPU 资源。 +4. **调用方中的串行处理**: 关键服务循环遍历项目,并一次调用一个嵌入式模型。 + +## 目标 + +**支持批量 API**: 允许在单个请求中处理多个文本。 +**向后兼容性**: 保持对单文本请求的支持。 +**显著的吞吐量提升**: 针对批量操作,目标是实现 5-10 倍的吞吐量提升。 +**每个文本的降低延迟**: 在嵌入多个文本时,降低平均延迟。 +**内存效率**: 在不产生过多内存消耗的情况下处理批量数据。 +**提供商无关性**: 支持 FastEmbed、Ollama 以及其他提供商的批量处理。 +**调用方迁移**: 更新所有嵌入式模型调用方,以便在有利的情况下使用批量 API。 + +## 背景 + +### 当前实现 - 嵌入式服务 + +位于 `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` 中的嵌入式实现存在显著的性能低效问题: + +```python +# fastembed/processor.py line 56 +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + + vecs = self.embeddings.embed([text]) # Single text wrapped in list + + return [v.tolist() for v in vecs] +``` + +**问题:** + +1. **批处理大小为 1:** FastEmbed 的 `embed()` 方法针对批量处理进行了优化,但我们总是使用 `[text]` - 批处理大小为 1。 + +2. **每个请求的开销:** 每次嵌入请求都涉及: + Pulsar 消息序列化/反序列化 + 网络往返延迟 + 模型推理启动开销 + Python 异步调度开销 + +3. **模式限制:** `EmbeddingsRequest` 模式仅支持单个文本: + ```python + @dataclass + class EmbeddingsRequest: + text: str = "" # Single text only + ``` + +### 当前调用者 - 序列化处理 + +#### 1. API 网关 + +**文件:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +网关通过 HTTP/WebSocket 接收单文本嵌入请求,并将它们转发到嵌入服务。目前没有批量端点。 + +```python +class EmbeddingsRequestor(ServiceRequestor): + # Handles single EmbeddingsRequest -> EmbeddingsResponse + request_schema=EmbeddingsRequest, # Single text only + response_schema=EmbeddingsResponse, +``` + +**影响:** 外部客户端(Web应用程序、脚本)必须发出N次HTTP请求才能嵌入N段文本。 + +#### 2. 文档嵌入服务 + +**文件:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +逐个处理文档块: + +```python +async def on_message(self, msg, consumer, flow): + v = msg.value() + + # Single chunk per request + resp = await flow("embeddings-request").request( + EmbeddingsRequest(text=v.chunk) + ) + vectors = resp.vectors +``` + +**影响:** 每个文档块都需要单独的嵌入调用。一个包含 100 个块的文档 = 100 个嵌入请求。 + +#### 3. 图嵌入服务 + +**文件:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + +循环遍历实体,并逐个嵌入每个实体: + +```python +async def on_message(self, msg, consumer, flow): + for entity in v.entities: + # Serial embedding - one entity at a time + vectors = await flow("embeddings-request").embed( + text=entity.context + ) + entities.append(EntityEmbeddings( + entity=entity.entity, + vectors=vectors, + chunk_id=entity.chunk_id, + )) +``` + +**影响:** 一个包含 50 个实体的消息意味着 50 个序列化的嵌入请求。这在知识图谱构建过程中是一个主要的瓶颈。 + +#### 4. 行嵌入服务 + +**文件:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + +循环遍历唯一的文本,并逐个嵌入每个文本: + +```python +async def on_message(self, msg, consumer, flow): + for text, (index_name, index_value) in texts_to_embed.items(): + # Serial embedding - one text at a time + vectors = await flow("embeddings-request").embed(text=text) + + embeddings_list.append(RowIndexEmbedding( + index_name=index_name, + index_value=index_value, + text=text, + vectors=vectors + )) +``` + +**影响:** 处理包含 100 个唯一索引值的表格 = 100 个序列化嵌入请求。 + +#### 5. EmbeddingsClient (基础客户端) + +**文件:** `trustgraph-base/trustgraph/base/embeddings_client.py` + +所有流程处理器使用的客户端仅支持单文本嵌入: + +```python +class EmbeddingsClient(RequestResponse): + async def embed(self, text, timeout=30): + resp = await self.request( + EmbeddingsRequest(text=text), # Single text + timeout=timeout + ) + return resp.vectors +``` + +**影响:** 所有使用此客户端的调用者都仅限于执行单文本操作。 + +#### 6. 命令行工具 + +**文件:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +命令行工具接受单个文本参数: + +```python +def query(url, flow_id, text, token=None): + result = flow.embeddings(text=text) # Single text + vectors = result.get("vectors", []) +``` + +**影响:** 用户无法通过命令行进行批量嵌入。处理一个文本文件需要 N 次调用。 + +#### 7. Python SDK + +Python SDK 提供了两个客户端类,用于与 TrustGraph 服务进行交互。这两个客户端类仅支持单文本嵌入。 + +**文件:** `trustgraph-base/trustgraph/api/flow.py` + +```python +class FlowInstance: + def embeddings(self, text): + """Get embeddings for a single text""" + input = {"text": text} + return self.request("service/embeddings", input)["vectors"] +``` + +**文件:** `trustgraph-base/trustgraph/api/socket_client.py` + +```python +class SocketFlowInstance: + def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]: + """Get embeddings for a single text via WebSocket""" + request = {"text": text} + return self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) +``` + +**影响:** 使用 SDK 的 Python 开发者必须循环遍历文本,并进行 N 次单独的 API 调用。 SDK 用户没有批量嵌入支持。 + +### 性能影响 + +对于典型的文档导入(1000 个文本块): +**当前:** 1000 个单独的请求,1000 次模型推理调用 +**批量(batch_size=32):** 32 个请求,32 次模型推理调用(减少 96.8%) + +对于图嵌入(包含 50 个实体的消息): +**当前:** 50 次序列等待调用,约 5-10 秒 +**批量:** 1-2 次批量调用,约 0.5-1 秒(提升 5-10 倍) + +FastEmbed 和类似库在批量大小达到硬件限制时,可以实现接近线性的吞吐量扩展(通常每个批次 32-128 个文本)。 + +## 技术设计 + +### 架构 + +嵌入批量处理优化需要修改以下组件: + +#### 1. **模式增强** + 扩展 `EmbeddingsRequest` 以支持多个文本 + 扩展 `EmbeddingsResponse` 以返回多个向量集合 + 保持与单文本请求的向后兼容性 + + 模块:`trustgraph-base/trustgraph/schema/services/llm.py` + +#### 2. **基础服务增强** + 更新 `EmbeddingsService` 以处理批量请求 + 添加批量大小配置 + 实现支持批量请求的处理逻辑 + + 模块:`trustgraph-base/trustgraph/base/embeddings_service.py` + +#### 3. **提供者处理器更新** + 更新 FastEmbed 处理器,将整个批次传递给 `embed()` + 更新 Ollama 处理器,以处理批次(如果支持) + 为不支持批处理的提供商添加回退的序列化处理 + + 模块: + `trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` + `trustgraph-flow/trustgraph/embeddings/ollama/processor.py` + +#### 4. **客户端增强** + 向 `EmbeddingsClient` 添加批量嵌入方法 + 支持单次和批量 API + 为大型输入添加自动批量处理 + + 模块:`trustgraph-base/trustgraph/base/embeddings_client.py` + +#### 5. **调用方更新 - 流处理器** + 更新 `graph_embeddings` 以批量实体上下文 + 更新 `row_embeddings` 以批量索引文本 + 如果消息批量处理可行,则更新 `document_embeddings` + + 模块: + `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py` + `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` + +#### 6. **API 网关增强** + 添加批量嵌入端点 + 支持请求体中的文本数组 + + 模块:`trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py` + +#### 7. **CLI 工具增强** + 添加对多个文本或文件输入的支持 + 添加批量大小参数 + + 模块:`trustgraph-cli/trustgraph/cli/invoke_embeddings.py` + +#### 8. **Python SDK 增强** + 向 `FlowInstance` 添加 `embeddings_batch()` 方法 + 向 `SocketFlowInstance` 添加 `embeddings_batch()` 方法 + 为 SDK 用户支持单次和批量 API + + 模块: + `trustgraph-base/trustgraph/api/flow.py` + `trustgraph-base/trustgraph/api/socket_client.py` + +### 数据模型 + +#### EmbeddingsRequest + +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +用法: +单个文本:`EmbeddingsRequest(texts=["hello world"])` +批量:`EmbeddingsRequest(texts=["text1", "text2", "text3"])` + +#### EmbeddingsResponse + +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +响应结构: +`vectors[i]` 包含用于 `texts[i]` 的向量集合。 +每个向量集合都是 `list[list[float]]` (模型可能为每个文本返回多个向量)。 +示例:3 个文本 → `vectors` 有 3 个条目,每个条目包含该文本的嵌入向量。 + +### API 接口 + +#### EmbeddingsClient + +```python +class EmbeddingsClient(RequestResponse): + async def embed( + self, + texts: list[str], + timeout: float = 300, + ) -> list[list[list[float]]]: + """ + Embed one or more texts in a single request. + + Args: + texts: List of texts to embed + timeout: Timeout for the operation + + Returns: + List of vector sets, one per input text + """ + resp = await self.request( + EmbeddingsRequest(texts=texts), + timeout=timeout + ) + if resp.error: + raise RuntimeError(resp.error.message) + return resp.vectors +``` + +#### API 网关嵌入式模型端点 + +更新后的端点支持单个或批量嵌入式模型: + +``` +POST /api/v1/embeddings +Content-Type: application/json + +{ + "texts": ["text1", "text2", "text3"], + "flow_id": "default" +} + +Response: +{ + "vectors": [ + [[0.1, 0.2, ...]], + [[0.3, 0.4, ...]], + [[0.5, 0.6, ...]] + ] +} +``` + +### 实现细节 + +#### 第一阶段:模式更改 + +**EmbeddingsRequest:** +```python +@dataclass +class EmbeddingsRequest: + texts: list[str] = field(default_factory=list) +``` + +**EmbeddingsResponse:** +```python +@dataclass +class EmbeddingsResponse: + error: Error | None = None + vectors: list[list[list[float]]] = field(default_factory=list) +``` + +**更新了 EmbeddingsService.on_request:** +```python +async def on_request(self, msg, consumer, flow): + request = msg.value() + id = msg.properties()["id"] + model = flow("model") + + vectors = await self.on_embeddings(request.texts, model=model) + response = EmbeddingsResponse(error=None, vectors=vectors) + + await flow("response").send(response, properties={"id": id}) +``` + +#### 第二阶段:FastEmbed 处理器更新 + +**当前(效率低下):** +```python +async def on_embeddings(self, text, model=None): + use_model = model or self.default_model + self._load_model(use_model) + vecs = self.embeddings.embed([text]) # Batch of 1 + return [v.tolist() for v in vecs] +``` + +**更新:** +```python +async def on_embeddings(self, texts: list[str], model=None): + """Embed texts - processes all texts in single model call""" + if not texts: + return [] + + use_model = model or self.default_model + self._load_model(use_model) + + # FastEmbed handles the full batch efficiently + all_vecs = list(self.embeddings.embed(texts)) + + # Return list of vector sets, one per input text + return [[v.tolist()] for v in all_vecs] +``` + +#### 第三阶段:图嵌入服务更新 + +**当前 (序列号):** +```python +async def on_message(self, msg, consumer, flow): + entities = [] + for entity in v.entities: + vectors = await flow("embeddings-request").embed(text=entity.context) + entities.append(EntityEmbeddings(...)) +``` + +**更新 (批量):** +```python +async def on_message(self, msg, consumer, flow): + # Collect all contexts + contexts = [entity.context for entity in v.entities] + + # Single batch embedding call + all_vectors = await flow("embeddings-request").embed(texts=contexts) + + # Pair results with entities + entities = [ + EntityEmbeddings( + entity=entity.entity, + vectors=vectors[0], # First vector from the set + chunk_id=entity.chunk_id, + ) + for entity, vectors in zip(v.entities, all_vectors) + ] +``` + +#### 第四阶段:行嵌入服务更新 + +**当前 (序列号):** +```python +for text, (index_name, index_value) in texts_to_embed.items(): + vectors = await flow("embeddings-request").embed(text=text) + embeddings_list.append(RowIndexEmbedding(...)) +``` + +**更新 (批量):** +```python +# Collect texts and metadata +texts = list(texts_to_embed.keys()) +metadata = list(texts_to_embed.values()) + +# Single batch embedding call +all_vectors = await flow("embeddings-request").embed(texts=texts) + +# Pair results +embeddings_list = [ + RowIndexEmbedding( + index_name=meta[0], + index_value=meta[1], + text=text, + vectors=vectors[0] # First vector from the set + ) + for text, meta, vectors in zip(texts, metadata, all_vectors) +] +``` + +#### 第五阶段:命令行工具增强 + +**更新后的命令行界面:** +```python +def main(): + parser = argparse.ArgumentParser(...) + + parser.add_argument( + 'text', + nargs='*', # Zero or more texts + help='Text(s) to convert to embedding vectors', + ) + + parser.add_argument( + '-f', '--file', + help='File containing texts (one per line)', + ) + + parser.add_argument( + '--batch-size', + type=int, + default=32, + help='Batch size for processing (default: 32)', + ) +``` + +用法: +```bash +# Single text (existing) +tg-invoke-embeddings "hello world" + +# Multiple texts +tg-invoke-embeddings "text one" "text two" "text three" + +# From file +tg-invoke-embeddings -f texts.txt --batch-size 64 +``` + +#### 第六阶段:Python SDK 增强 + +**FlowInstance (HTTP 客户端):** + +```python +class FlowInstance: + def embeddings(self, texts: list[str]) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + input = {"texts": texts} + return self.request("service/embeddings", input)["vectors"] +``` + +**SocketFlowInstance (WebSocket 客户端):** + +```python +class SocketFlowInstance: + def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]: + """ + Get embeddings for one or more texts via WebSocket. + + Args: + texts: List of texts to embed + + Returns: + List of vector sets, one per input text + """ + request = {"texts": texts} + response = self.client._send_request_sync( + "embeddings", self.flow_id, request, False + ) + return response["vectors"] +``` + +**SDK 使用示例:** + +```python +# Single text +vectors = flow.embeddings(["hello world"]) +print(f"Dimensions: {len(vectors[0][0])}") + +# Batch embedding +texts = ["text one", "text two", "text three"] +all_vectors = flow.embeddings(texts) + +# Process results +for text, vecs in zip(texts, all_vectors): + print(f"{text}: {len(vecs[0])} dimensions") +``` + +## 安全注意事项 + +**请求大小限制**: 强制执行最大批处理大小,以防止资源耗尽。 +**超时处理**: 针对批处理大小,适当调整超时时间。 +**内存限制**: 监控大型批处理的内存使用情况。 +**输入验证**: 在处理之前,验证批处理中的所有文本。 + +## 性能注意事项 + +### 预期改进 + +**吞吐量**: +单个文本: ~10-50 文本/秒 (取决于模型) +批处理 (大小 32): ~200-500 文本/秒 (提升 5-10 倍) + +**每个文本的延迟**: +单个文本: 每个文本 50-200 毫秒 +批处理 (大小 32): 每个文本 5-20 毫秒 (摊销值) + +**特定服务的改进**: + +| 服务 | 当前 | 批处理 | 改进 | +|---------|---------|---------|-------------| +| 图嵌入 (50 个实体) | 5-10 秒 | 0.5-1 秒 | 5-10 倍 | +| 行嵌入 (100 个文本) | 10-20 秒 | 1-2 秒 | 5-10 倍 | +| 文档导入 (1000 个块) | 100-200 秒 | 10-30 秒 | 5-10 倍 | + +### 配置参数 + +```python +# Recommended defaults +DEFAULT_BATCH_SIZE = 32 +MAX_BATCH_SIZE = 128 +BATCH_TIMEOUT_MULTIPLIER = 2.0 +``` + +## 测试策略 + +### 单元测试 +单个文本嵌入(向后兼容) +空批处理的处理 +最大批处理大小的强制执行 +部分批处理失败的错误处理 + +### 集成测试 +通过 Pulsar 进行端到端批处理嵌入 +图嵌入服务批处理 +行嵌入服务批处理 +API 网关批处理端点 + +### 性能测试 +比较单批和批量吞吐量 +在各种批处理大小下的内存使用情况 +延迟分布分析 + +## 迁移计划 + +这是一个破坏性更改版本。所有阶段都一起实施。 + +### 第一阶段:Schema 更改 +将 EmbeddingsRequest 中的 `text: str` 替换为 `texts: list[str]` +将 EmbeddingsResponse 中的 `vectors` 类型更改为 `list[list[list[float]]]` + +### 第二阶段:处理器更新 +更新 FastEmbed 和 Ollama 处理器中的 `on_embeddings` 签名 +在单个模型调用中处理整个批次 + +### 第三阶段:客户端更新 +更新 `EmbeddingsClient.embed()` 以接受 `texts: list[str]` + +### 第四阶段:调用方更新 +更新 graph_embeddings 以批处理实体上下文 +更新 row_embeddings 以批处理索引文本 +更新 document_embeddings 以使用新的 Schema +更新 CLI 工具 + +### 第五阶段:API 网关 +更新用于新 Schema 的嵌入端点 + +### 第六阶段:Python SDK +更新 `FlowInstance.embeddings()` 签名 +更新 `SocketFlowInstance.embeddings()` 签名 + +## 开放问题 + +**大型批处理的流式传输**: 我们是否应该支持对非常大的批处理(>100 个文本)进行流式传输结果? +**特定于提供商的限制**: 我们应该如何处理具有不同最大批处理大小的提供商? +**部分失败处理**: 如果批处理中的一个文本失败,我们应该使整个批处理失败,还是返回部分结果? +**文档嵌入批处理**: 我们应该跨多个 Chunk 消息进行批处理,还是保持每个消息的处理? + +## 参考文献 + +[FastEmbed 文档](https://github.com/qdrant/fastembed) +[Ollama 嵌入 API](https://github.com/ollama/ollama) +[EmbeddingsService 实现](trustgraph-base/trustgraph/base/embeddings_service.py) +[GraphRAG 性能优化](graphrag-performance-optimization.md) diff --git a/docs/tech-specs/entity-centric-graph.ar.md b/docs/tech-specs/entity-centric-graph.ar.md new file mode 100644 index 00000000..ecfb6947 --- /dev/null +++ b/docs/tech-specs/entity-centric-graph.ar.md @@ -0,0 +1,261 @@ +# تخزين الرسم البياني المعرفي المرتكز على الكيانات على Cassandra + +## نظرة عامة + +يصف هذا المستند نموذج تخزين للرسوم البيانية المعرفية بنمط RDF على Apache Cassandra. يستخدم النموذج نهجًا **مرتكزًا على الكيانات** حيث يعرف كل كيان كل رباعية يشارك فيها والدور الذي يلعبه. هذا يحل محل نهج تبديل SPO متعدد الجداول باستخدام جدولين فقط. + +## الخلفية والدوافع + +### النهج التقليدي + +يتطلب متجر رباعي RDF قياسي على Cassandra جداول متعددة غير طبيعية لتغطية أنماط الاستعلام - عادةً 6 جداول أو أكثر تمثل تبديلات مختلفة للموضوع والمسند والموضوع ومجموعة البيانات (SPOD). يتم كتابة كل رباعية في كل جدول، مما يؤدي إلى تضخيم كبير في عمليات الكتابة، والنفقات التشغيلية، وتعقيد المخطط. + +بالإضافة إلى ذلك، يتطلب تحليل التسميات (جلب أسماء قابلة للقراءة للبشر للكيانات) استعلامات إضافية، وهو أمر مكلف بشكل خاص في حالات استخدام الذكاء الاصطناعي و GraphRAG حيث تعتبر التسميات ضرورية لسياق LLM. + +### الرؤية المرتكزة على الكيانات + +تتضمن كل رباعية `(D, S, P, O)` ما يصل إلى 4 كيانات. من خلال كتابة صف لكل مشاركة للكيان في الرباعية، نضمن أن **أي استعلام يحتوي على عنصر معروف واحد سيضرب مفتاح التقسيم**. يغطي هذا جميع أنماط الاستعلام الـ 16 باستخدام جدول بيانات واحد. + +الفوائد الرئيسية: + +**جدولان** بدلاً من 7 أو أكثر +**4 عمليات كتابة لكل رباعية** بدلاً من 6 أو أكثر +**تحليل التسميات مجانًا** - يتم تخزين تسميات الكيان مع علاقاته، مما يؤدي بشكل طبيعي إلى تسخين ذاكرة التخزين المؤقت للتطبيق +**جميع أنماط الاستعلام الـ 16** يتم تقديمها من خلال قراءات ذات قسم واحد +**عمليات أبسط** - جدول بيانات واحد للضبط والضغط والإصلاح + +## المخطط + +### الجدول 1: quads_by_entity + +الجدول الرئيسي للبيانات. يحتوي كل كيان على قسم يحتوي على جميع الرباعيات التي يشارك فيها. تم تسميته ليعكس نمط الاستعلام (البحث حسب الكيان). + +```sql +CREATE TABLE quads_by_entity ( + collection text, -- Collection/tenant scope (always specified) + entity text, -- The entity this row is about + role text, -- 'S', 'P', 'O', 'G' — how this entity participates + p text, -- Predicate of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + s text, -- Subject of the quad + o text, -- Object of the quad + d text, -- Dataset/graph of the quad + dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string' + lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr' + PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang) +); +``` + +**مفتاح التقسيم:** `(collection, entity)` - محدد للنطاق ضمن المجموعة، قسم واحد لكل كيان. + +**المنطق وراء ترتيب أعمدة التجميع:** + +1. **role** - معظم الاستعلامات تبدأ بـ "أين يقع هذا الكيان كموضوع/موضوع؟" +2. **p** - المرشح الأكثر شيوعًا بعد ذلك، "أعطني جميع `knows` العلاقات". +3. **otype** - يتيح التصفية حسب العلاقات ذات القيم المحددة بواسطة URI مقابل العلاقات ذات القيم الحرفية. +4. **s, o, d** - الأعمدة المتبقية لضمان التفرد. +5. **dtype, lang** - التمييز بين القيم الحرفية التي لها نفس القيمة ولكن بيانات تعريف نوع مختلفة (على سبيل المثال، `"thing"` مقابل `"thing"@en` مقابل `"thing"^^xsd:string`). + +### الجدول 2: quads_by_collection + +يدعم الاستعلامات والإجراءات الحذف على مستوى المجموعة. يوفر قائمة بجميع الرباعيات التي تنتمي إلى مجموعة. تم تسميته ليعكس نمط الاستعلام (البحث حسب المجموعة). + +```sql +CREATE TABLE quads_by_collection ( + collection text, + d text, -- Dataset/graph of the quad + s text, -- Subject of the quad + p text, -- Predicate of the quad + o text, -- Object of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + dtype text, -- XSD datatype (when otype = 'L') + lang text, -- Language tag (when otype = 'L') + PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang) +); +``` + +يتم التجميع بناءً على مجموعة البيانات أولاً، مما يتيح الحذف على مستوى المجموعة أو مستوى مجموعة البيانات. يتم تضمين الأعمدة `otype` و `dtype` و `lang` في مفتاح التجميع للتمييز بين القيم الحرفية التي لها نفس القيمة ولكن بيانات تعريف نوع مختلفة - في RDF، `"thing"` و `"thing"@en` و `"thing"^^xsd:string` هي قيم متميزة دلاليًا. + +## مسار الكتابة + +لكل مجموعة رباعية `(D, S, P, O)` واردة ضمن مجموعة `C`، اكتب **4 صفوف** إلى `quads_by_entity` و **صف واحد** إلى `quads_by_collection`. + +### مثال + +بالنظر إلى المجموعة الرباعية في المجموعة `tenant1`: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: https://example.org/knows +Object: https://example.org/Bob +``` + +اكتب 4 صفوف إلى `quads_by_entity`: + +| collection | entity | role | p | otype | s | o | d | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | + +اكتب صفًا واحدًا إلى `quads_by_collection`: + +| collection | d | s | p | o | otype | dtype | lang | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | | + +### مثال حرفي + +بالنسبة لثلاثية التسمية: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: http://www.w3.org/2000/01/rdf-schema#label +Object: "Alice Smith" (lang: en) +``` + +الرمز `otype` هو `'L'`، و `dtype` هو `'xsd:string'`، و `lang` هو `'en'`. يتم تخزين القيمة الحرفية `"Alice Smith"` في `o`. هناك حاجة إلى 3 صفوف فقط في `quads_by_entity` - لا يتم كتابة أي صف للقيمة الحرفية ككيان، نظرًا لأن القيم الحرفية ليست كيانات قابلة للاستعلام بشكل مستقل. + +## أنماط الاستعلام + +### جميع أنماط DSPO الـ 16 + +في الجدول أدناه، تعني عبارة "بادئة مثالية" أن الاستعلام يستخدم بادئة متجاورة لأعمدة التجميع. تعني عبارة "فحص التقسيم + التصفية" أن Cassandra تقرأ جزءًا من التقسيم وتقوم بالتصفية في الذاكرة - لا يزال فعالاً، ولكنه ليس تطابقًا خالصًا للبادئة. + +| # | Known | Lookup entity | Clustering prefix | Efficiency | +|---|---|---|---|---| +| 1 | D,S,P,O | entity=S, role='S', p=P | تطابق كامل | بادئة مثالية | +| 2 | D,S,P,? | entity=S, role='S', p=P | التصفية على D | فحص التقسيم + التصفية | +| 3 | D,S,?,O | entity=S, role='S' | التصفية على D، O | فحص التقسيم + التصفية | +| 4 | D,?,P,O | entity=O, role='O', p=P | التصفية على D | فحص التقسيم + التصفية | +| 5 | ?,S,P,O | entity=S, role='S', p=P | التصفية على O | فحص التقسيم + التصفية | +| 6 | D,S,?,? | entity=S, role='S' | التصفية على D | فحص التقسيم + التصفية | +| 7 | D,?,P,? | entity=P, role='P' | التصفية على D | فحص التقسيم + التصفية | +| 8 | D,?,?,O | entity=O, role='O' | التصفية على D | فحص التقسيم + التصفية | +| 9 | ?,S,P,? | entity=S, role='S', p=P | — | **بادئة مثالية** | +| 10 | ?,S,?,O | entity=S, role='S' | التصفية على O | فحص التقسيم + التصفية | +| 11 | ?,?,P,O | entity=O, role='O', p=P | — | **بادئة مثالية** | +| 12 | D,?,?,? | entity=D, role='G' | — | **بادئة مثالية** | +| 13 | ?,S,?,? | entity=S, role='S' | — | **بادئة مثالية** | +| 14 | ?,?,P,? | entity=P, role='P' | — | **بادئة مثالية** | +| 15 | ?,?,?,O | entity=O, role='O' | — | **بادئة مثالية** | +| 16 | ?,?,?,? | — | فحص كامل | استكشاف فقط | + +**النتيجة الرئيسية:** 7 من أنماط الـ 15 غير التافهة هي تطابقات مثالية لبادئة التجميع. أما الـ 8 المتبقية فهي قراءات لتقسيم واحد مع تصفية داخل التقسيم. كل استعلام يحتوي على عنصر معروف واحد يطابق مفتاح التقسيم. + +نمط 16 (?,?,?,?) لا يحدث في الممارسة العملية لأنه يتم دائمًا تحديد المجموعة، مما يقلله إلى النمط 12. + +### أمثلة شائعة للاستعلام + +**كل شيء عن كيان:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'; +``` + +**جميع العلاقات الخارجة لكيان:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S'; +``` + +**شرط محدد لكيان:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows'; +``` + +**تسمية لكيان (بلغة محددة):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label' +AND otype = 'L'; +``` + +ثم قم بالتصفية باستخدام `lang = 'en'` من جانب التطبيق إذا لزم الأمر. + +**فقط العلاقات التي تحمل قيمًا من نوع URI (روابط من كيان إلى كيان):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U'; +``` + +**البحث العكسي - ما الذي يشير إلى هذا الكيان:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob' +AND role = 'O'; +``` + +## حل التسميات وتدفئة ذاكرة التخزين المؤقت + +أحد أهم مزايا النموذج المرتكز على الكيانات هو أن **يصبح حل التسميات تأثيرًا ثانويًا مجانيًا**. + +في النموذج التقليدي متعدد الجداول، يتطلب استرداد التسميات استعلامات منفصلة: استرداد الثلاثيات، وتحديد معرفات الكيانات في النتائج، ثم استرداد `rdfs:label` لكل منها. هذا النمط N+1 مكلف. + +في النموذج المرتكز على الكيانات، يُرجع الاستعلام عن كيان **جميع** رباعياته - بما في ذلك تسمياته وأنواعه وخصائصه الأخرى. عندما يقوم التطبيق بتخزين نتائج الاستعلام مؤقتًا، يتم تدفئة التسميات مسبقًا قبل أن يطلبها أي شيء. + +يؤكد نظامان للاستخدام على أن هذا يعمل بشكل جيد في الممارسة: + +**الاستعلامات الموجهة للمستخدم**: مجموعات نتائج صغيرة بشكل طبيعي، والتسميات ضرورية. يؤدي قراءة الكيانات إلى تدفئة ذاكرة التخزين المؤقت مسبقًا. +**استعلامات الذكاء الاصطناعي/الكمية الكبيرة**: مجموعات نتائج كبيرة مع حدود صارمة. التسميات إما غير ضرورية أو مطلوبة فقط لمجموعة فرعية من الكيانات تم تخزينها بالفعل في ذاكرة التخزين المؤقت. + +يتم تخفيف المخاوف النظرية المتعلقة بحل التسميات لمجموعات نتائج ضخمة (مثل 30000 كيان) بالملاحظة العملية القائلة بأنه لا يمكن لأي مستهلك بشري أو ذكاء اصطناعي معالجة هذا العدد الكبير من التسميات. تضمن حدود الاستعلام على مستوى التطبيق أن يظل ضغط ذاكرة التخزين المؤقت قابلاً للإدارة. + +## التقسيمات العريضة وإعادة التعريف + +يؤدي إعادة التعريف (عبارات على شكل RDF-star حول العبارات) إلى إنشاء كيانات مركزية - على سبيل المثال، مستند مصدر يدعم آلاف الحقائق المستخرجة. يمكن أن يؤدي هذا إلى تقسيمات عريضة. + +عوامل تخفيف: + +**حدود الاستعلام على مستوى التطبيق**: تفرض جميع استعلامات GraphRAG والاستعلامات الموجهة للمستخدم حدودًا صارمة، لذلك لا يتم فحص التقسيمات العريضة بالكامل على مسار القراءة الساخنة. +**تتعامل Cassandra بكفاءة مع القراءات الجزئية**: يعد فحص عمود التجميع مع إيقاف مبكر أمرًا سريعًا حتى على التقسيمات الكبيرة. +**حذف المجموعة** (العملية الوحيدة التي قد تتجاوز التقسيمات الكاملة) هي عملية خلفية مقبولة. + +## حذف المجموعة + +يتم تشغيله بواسطة استدعاء واجهة برمجة التطبيقات، ويعمل في الخلفية (متسق في النهاية). + +1. اقرأ `quads_by_collection` للمجموعة المستهدفة للحصول على جميع الرباعيات. +2. استخرج الكيانات الفريدة من الرباعيات (قيم s و p و o و d). +3. لكل كيان فريد، احذف التقسيم من `quads_by_entity`. +4. احذف الصفوف من `quads_by_collection`. + +يوفر جدول `quads_by_collection` الفهرس المطلوب لتحديد موقع جميع تقسيمات الكيانات دون فحص كامل للجدول. عمليات حذف التقسيمات فعالة نظرًا لأن `(collection, entity)` هو مفتاح التقسيم. + +## مسار الترحيل من النموذج متعدد الجداول + +يمكن للنموذج المرتكز على الكيانات أن يتعايش مع النموذج متعدد الجداول الحالي أثناء الترحيل: + +1. نشر جداول `quads_by_entity` و `quads_by_collection` جنبًا إلى جنب مع الجداول الحالية. +2. الكتابة المزدوجة للرباعيات الجديدة إلى كل من الجداول القديمة والجديدة. +3. ملء البيانات الموجودة في الجداول الجديدة. +4. ترحيل مسارات القراءة نمط استعلام واحد في كل مرة. +5. إلغاء تنشيط الجداول القديمة بمجرد ترحيل جميع عمليات القراءة. + +## ملخص + +| الجانب | تقليدي (6 جداول) | مرتكز على الكيانات (جدولان) | +|---|---|---| +| الجداول | 7+ | 2 | +| عمليات الكتابة لكل رباعية | 6+ | 5 (4 بيانات + 1 بيان) | +| حل التسميات | استعلامات منفصلة | مجاني عبر تدفئة ذاكرة التخزين المؤقت | +| أنماط الاستعلام | 16 عبر 6 جداول | 16 على جدول واحد | +| تعقيد المخطط | مرتفع | منخفض | +| النفقات التشغيلية | 6 جداول للتعديل/الإصلاح | جدول بيانات واحد | +| دعم إعادة التعريف | تعقيد إضافي | مناسب بشكل طبيعي | +| تصفية أنواع الكائنات | غير متوفر | أصلي (عبر التجميع حسب نوع الكائن) | + diff --git a/docs/tech-specs/entity-centric-graph.es.md b/docs/tech-specs/entity-centric-graph.es.md new file mode 100644 index 00000000..d42caa06 --- /dev/null +++ b/docs/tech-specs/entity-centric-graph.es.md @@ -0,0 +1,261 @@ +# Almacenamiento de Grafos de Conocimiento Centrados en Entidades en Cassandra + +## Resumen + +Este documento describe un modelo de almacenamiento para grafos de conocimiento de estilo RDF en Apache Cassandra. El modelo utiliza un enfoque **centrado en entidades** donde cada entidad conoce cada cuadrupla en la que participa y el rol que juega. Esto reemplaza un enfoque tradicional de permutaciones SPO con múltiples tablas con solo dos tablas. + +## Antecedentes y Motivación + +### El Enfoque Tradicional + +Un almacén de cuádruplas RDF estándar en Cassandra requiere múltiples tablas desnormalizadas para cubrir los patrones de consulta, normalmente de 6 o más tablas que representan diferentes permutaciones de Sujeto, Predicado, Objeto y Conjunto de Datos (SPOD). Cada cuadrupla se escribe en cada tabla, lo que resulta en una amplificación de escritura significativa, una sobrecarga operativa y una complejidad del esquema. + +Además, la resolución de etiquetas (obtención de nombres legibles para humanos para las entidades) requiere consultas de ida y vuelta separadas, lo que es particularmente costoso en casos de uso de IA y GraphRAG donde las etiquetas son esenciales para el contexto de los LLM. + +### La Perspectiva Centrada en Entidades + +Cada cuadrupla `(D, S, P, O)` involucra hasta 4 entidades. Al escribir una fila para la participación de cada entidad en la cuadrupla, garantizamos que **cualquier consulta con al menos un elemento conocido golpeará una clave de partición**. Esto cubre los 16 patrones de consulta con una sola tabla de datos. + +Beneficios clave: + +**2 tablas** en lugar de 7+ +**4 escrituras por cuadrupla** en lugar de 6+ +**Resolución de etiquetas de forma gratuita**: las etiquetas de una entidad están ubicadas junto con sus relaciones, lo que calienta naturalmente la caché de la aplicación. +**Los 16 patrones de consulta** se sirven mediante lecturas de partición única. +**Operaciones más simples**: una sola tabla de datos para ajustar, compactar y reparar. + +## Esquema + +### Tabla 1: quads_by_entity + +La tabla de datos principal. Cada entidad tiene una partición que contiene todas las cuádruplas en las que participa. Nombrada para reflejar el patrón de consulta (búsqueda por entidad). +Después de la última línea traducida, incluir una línea final que contenga exactamente: [[__END_OF_TRANSLATION__]] +```sql +CREATE TABLE quads_by_entity ( + collection text, -- Collection/tenant scope (always specified) + entity text, -- The entity this row is about + role text, -- 'S', 'P', 'O', 'G' — how this entity participates + p text, -- Predicate of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + s text, -- Subject of the quad + o text, -- Object of the quad + d text, -- Dataset/graph of the quad + dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string' + lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr' + PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang) +); +``` + +**Clave de partición**: `(collection, entity)` — con alcance a la colección, una partición por entidad. + +**Justificación del orden de las columnas de clustering**: + +1. **role** — la mayoría de las consultas comienzan con "dónde está esta entidad como sujeto/objeto". +2. **p** — el siguiente filtro más común, "muéstrame todas las relaciones `knows`". +3. **otype** — permite filtrar por relaciones con valores URI frente a relaciones con valores literales. +4. **s, o, d** — columnas restantes para la unicidad. +5. **dtype, lang** — distingue literales con el mismo valor pero con diferentes metadatos de tipo (por ejemplo, `"thing"` vs `"thing"@en` vs `"thing"^^xsd:string`). + +### Tabla 2: quads_by_collection + +Soporta consultas y eliminaciones a nivel de colección. Proporciona un manifiesto de todos los cuads pertenecientes a una colección. Nombrado para reflejar el patrón de consulta (búsqueda por colección). + +```sql +CREATE TABLE quads_by_collection ( + collection text, + d text, -- Dataset/graph of the quad + s text, -- Subject of the quad + p text, -- Predicate of the quad + o text, -- Object of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + dtype text, -- XSD datatype (when otype = 'L') + lang text, -- Language tag (when otype = 'L') + PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang) +); +``` + +Agrupados primero por conjunto de datos, lo que permite la eliminación a nivel de colección o de conjunto de datos. Las columnas `otype`, `dtype` y `lang` se incluyen en la clave de agrupación para distinguir literales con el mismo valor pero con diferentes metadatos de tipo; en RDF, `"thing"`, `"thing"@en` y `"thing"^^xsd:string` son valores semánticamente distintos. + +## Ruta de escritura + +Para cada cuadruple entrante `(D, S, P, O)` dentro de una colección `C`, escriba **4 filas** en `quads_by_entity` y **1 fila** en `quads_by_collection`. + +### Ejemplo + +Dado el cuadruple en la colección `tenant1`: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: https://example.org/knows +Object: https://example.org/Bob +``` + +Escriba 4 filas en `quads_by_entity`: + +| collection | entity | role | p | otype | s | o | d | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | + +Escriba 1 fila en `quads_by_collection`: + +| collection | d | s | p | o | otype | dtype | lang | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | | + +### Ejemplo Literal + +Para una tripleta de etiqueta: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: http://www.w3.org/2000/01/rdf-schema#label +Object: "Alice Smith" (lang: en) +``` + +El `otype` es `'L'`, `dtype` es `'xsd:string'`, y `lang` es `'en'`. El valor literal `"Alice Smith"` se almacena en `o`. Solo se necesitan 3 filas en `quads_by_entity`; no se escribe ninguna fila para el literal como entidad, ya que los literales no son entidades consultables de forma independiente. + +## Patrones de consulta + +### Los 16 patrones DSPO + +En la tabla a continuación, "Prefijo perfecto" significa que la consulta utiliza un prefijo contiguo de las columnas de clustering. "Escaneo de partición + filtro" significa que Cassandra lee una porción de una partición y filtra en memoria; es eficiente, pero no es una coincidencia de prefijo pura. + +| # | Conocido | Búsqueda de entidad | Prefijo de clustering | Eficiencia | +|---|---|---|---|---| +| 1 | D,S,P,O | entidad=S, rol='S', p=P | Coincidencia completa | Prefijo perfecto | +| 2 | D,S,P,? | entidad=S, rol='S', p=P | Filtro en D | Escaneo de partición + filtro | +| 3 | D,S,?,O | entidad=S, rol='S' | Filtro en D, O | Escaneo de partición + filtro | +| 4 | D,?,P,O | entidad=O, rol='O', p=P | Filtro en D | Escaneo de partición + filtro | +| 5 | ?,S,P,O | entidad=S, rol='S', p=P | Filtro en O | Escaneo de partición + filtro | +| 6 | D,S,?,? | entidad=S, rol='S' | Filtro en D | Escaneo de partición + filtro | +| 7 | D,?,P,? | entidad=P, rol='P' | Filtro en D | Escaneo de partición + filtro | +| 8 | D,?,?,O | entidad=O, rol='O' | Filtro en D | Escaneo de partición + filtro | +| 9 | ?,S,P,? | entidad=S, rol='S', p=P | — | **Prefijo perfecto** | +| 10 | ?,S,?,O | entidad=S, rol='S' | Filtro en O | Escaneo de partición + filtro | +| 11 | ?,?,P,O | entidad=O, rol='O', p=P | — | **Prefijo perfecto** | +| 12 | D,?,?,? | entidad=D, rol='G' | — | **Prefijo perfecto** | +| 13 | ?,S,?,? | entidad=S, rol='S' | — | **Prefijo perfecto** | +| 14 | ?,?,P,? | entidad=P, rol='P' | — | **Prefijo perfecto** | +| 15 | ?,?,?,O | entidad=O, rol='O' | — | **Prefijo perfecto** | +| 16 | ?,?,?,? | — | Escaneo completo | Exploración solo | + +**Resultado clave**: 7 de los 15 patrones no triviales son coincidencias perfectas de prefijo de clustering. Los 8 restantes son lecturas de partición única con filtrado dentro de la partición. Cada consulta con al menos un elemento conocido coincide con una clave de partición. + +El patrón 16 (?,?,?,?) no ocurre en la práctica, ya que la colección siempre se especifica, lo que lo reduce al patrón 12. + +### Ejemplos comunes de consultas + +**Todo sobre una entidad:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'; +``` + +**Todas las relaciones de salida para una entidad:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S'; +``` + +**Predicado específico para una entidad:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows'; +``` + +**Etiqueta para una entidad (idioma específico):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label' +AND otype = 'L'; +``` + +Luego, filtre según la aplicación `lang = 'en'`, si es necesario. + +**Solo relaciones con valores URI (enlaces de entidad a entidad):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U'; +``` + +**Búsqueda inversa: ¿a qué entidades hace referencia esta?** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob' +AND role = 'O'; +``` + +## Resolución de etiquetas y calentamiento de la caché + +Una de las ventajas más significativas del modelo centrado en entidades es que **la resolución de etiquetas se convierte en un efecto secundario gratuito**. + +En el modelo tradicional de múltiples tablas, recuperar etiquetas requiere consultas separadas: recuperar triples, identificar los URI de las entidades en los resultados y luego recuperar `rdfs:label` para cada uno. Este patrón N+1 es costoso. + +En el modelo centrado en entidades, consultar una entidad devuelve **todos** sus cuads, incluidas sus etiquetas, tipos y otras propiedades. Cuando la aplicación almacena en caché los resultados de las consultas, las etiquetas se precalientan antes de que alguien las solicite. + +Dos regímenes de uso confirman que esto funciona bien en la práctica: + +**Consultas orientadas al usuario**: conjuntos de resultados naturalmente pequeños, las etiquetas son esenciales. Las lecturas de entidades precalientan la caché. +**Consultas de IA/masivas**: conjuntos de resultados grandes con límites estrictos. Las etiquetas son innecesarias o se necesitan solo para un subconjunto curado de entidades que ya están en la caché. + +La preocupación teórica de resolver etiquetas para conjuntos de resultados enormes (por ejemplo, 30 000 entidades) se mitiga por la observación práctica de que ningún consumidor humano o de IA procesa útilmente tantas etiquetas. Los límites de consulta a nivel de aplicación garantizan que la presión de la caché siga siendo manejable. + +## Particiones anchas y reificación + +La reificación (declaraciones RDF-star sobre declaraciones) crea entidades de centro, por ejemplo, un documento de origen que admite miles de hechos extraídos. Esto puede producir particiones anchas. + +Factores atenuantes: + +**Límites de consulta a nivel de aplicación**: todas las consultas de GraphRAG y orientadas al usuario imponen límites estrictos, por lo que las particiones anchas nunca se escanean completamente en la ruta de lectura activa. +**Cassandra maneja las lecturas parciales de manera eficiente**: un escaneo de columna de agrupación con una parada temprana es rápido incluso en particiones grandes. +**Eliminación de colecciones** (la única operación que podría recorrer particiones completas) es un proceso de segundo plano aceptable. + +## Eliminación de colecciones + +Se activa mediante una llamada a la API, se ejecuta en segundo plano (consistencia eventual). + +1. Leer `quads_by_collection` para la colección de destino para obtener todos los cuads. +2. Extraer entidades únicas de los cuads (valores s, p, o, d). +3. Para cada entidad única, eliminar la partición de `quads_by_entity`. +4. Eliminar las filas de `quads_by_collection`. + +La tabla `quads_by_collection` proporciona el índice necesario para localizar todas las particiones de entidades sin un escaneo completo de la tabla. Las eliminaciones a nivel de partición son eficientes porque `(collection, entity)` es la clave de partición. + +## Ruta de migración desde el modelo de múltiples tablas + +El modelo centrado en entidades puede coexistir con el modelo de múltiples tablas existente durante la migración: + +1. Implementar las tablas `quads_by_entity` y `quads_by_collection` junto con las tablas existentes. +2. Escribir duplicados nuevos cuads tanto en las tablas antiguas como en las nuevas. +3. Rellenar los datos existentes en las nuevas tablas. +4. Migrar las rutas de consulta un patrón a la vez. +5. Desactivar las tablas antiguas una vez que todas las lecturas se hayan migrado. + +## Resumen + +| Aspecto | Tradicional (6 tablas) | Centrado en entidades (2 tablas) | +|---|---|---| +| Tablas | 7+ | 2 | +| Escrituras por quad | 6+ | 5 (4 datos + 1 manifiesto) | +| Resolución de etiquetas | Viajes separados | Gratuito a través del calentamiento de la caché | +| Patrones de consulta | 16 en 6 tablas | 16 en 1 tabla | +| Complejidad del esquema | Alto | Bajo | +| Sobrecarga operativa | 6 tablas para ajustar/reparar | 1 tabla de datos | +| Soporte de reificación | Complejidad adicional | Ajuste natural | +| Filtrado de tipo de objeto | No disponible | Nativo (a través de la agrupación de otype) | +Después de la última línea traducida, incluir una línea final que contenga exactamente: [[__END_OF_TRANSLATION__]] diff --git a/docs/tech-specs/entity-centric-graph.he.md b/docs/tech-specs/entity-centric-graph.he.md new file mode 100644 index 00000000..411f8130 --- /dev/null +++ b/docs/tech-specs/entity-centric-graph.he.md @@ -0,0 +1,261 @@ +# אחסון גרף ידע ממוקד ישויות ב-Cassandra + +## סקירה כללית + +מסמך זה מתאר מודל אחסון עבור גרפי ידע מסוג RDF ב-Apache Cassandra. המודל משתמש בגישה **ממוקדת ישויות**, כאשר כל ישות יודעת כל רביעיות (quads) בהן היא משתתפת והתפקיד שלה. זה מחליף גישה מסורתית של מספר טבלאות המייצגות את כל הפרמוטציות של Subject, Predicate, Object ו-Dataset (SPOD) עם שתי טבלאות בלבד. + +## רקע ומניעים + +### הגישה המסורתית + +חנות רביעיות RDF סטנדרטית ב-Cassandra דורשת מספר טבלאות לא מנורמלות כדי לכסות דפוסי שאילתות - בדרך כלל 6 טבלאות או יותר המייצגות את הפרמוטציות השונות של Subject, Predicate, Object ו-Dataset (SPOD). כל רביעייה נכתבת לכל טבלה, מה שגורם להגדלת כתיבה משמעותית, תקורה תפעולית ומורכבות סכימה. + +בנוסף, פתרון תוויות (שליפת שמות קריאים לבני אדם עבור ישויות) דורש שאילתות נפרדות, דבר שיכול להיות יקר במיוחד במקרי שימוש של AI ו-GraphRAG, שבהם תוויות חיוניות להקשר של מודלי שפה גדולים (LLM). + +### התובנה הממוקדת בישות + +כל רביעייה `(D, S, P, O)` כוללת עד 4 ישויות. על ידי כתיבת שורה עבור כל השתתפות של ישות ברביעייה, אנו מבטיחים ש-**כל שאילתה עם לפחות רכיב אחד ידוע תפגע במפתח מחיצה**. זה מכסה את כל 16 דפוסי השאילתות עם טבלת נתונים אחת. + +יתרונות עיקריים: + +**2 טבלאות** במקום 7+ +**4 כתיבות לרביעייה** במקום 6+ +**פתרון תוויות בחינם** - התוויות של ישות נמצאות יחד עם הקשרים שלה, מה שמחמם באופן טבעי את מטמון האפליקציה. +**כל 16 דפוסי השאילתות** נגישים באמצעות קריאות מחיצה יחידה. +**פעולות פשוטות יותר** - טבלת נתונים אחת לכוונן, לדחוס ולתקן. + +## סכימה + +### טבלה 1: quads_by_entity + +טבלת הנתונים העיקרית. לכל ישות יש מחיצה המכילה את כל הרביעיות בהן היא משתתפת. נקראה כך כדי לשקף את דפוס השאילתה (חיפוש לפי ישות). +פלט חוזה (יש לעקוב אחר הפורמט המדויק). +```sql +CREATE TABLE quads_by_entity ( + collection text, -- Collection/tenant scope (always specified) + entity text, -- The entity this row is about + role text, -- 'S', 'P', 'O', 'G' — how this entity participates + p text, -- Predicate of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + s text, -- Subject of the quad + o text, -- Object of the quad + d text, -- Dataset/graph of the quad + dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string' + lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr' + PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang) +); +``` + +**מפתח מחיצה**: `(collection, entity)` — מוגבל לאוסף, מחיצה אחת לכל ישות. + +**ההצדקה עבור סדר עמודי הצבירה**: + +1. **role** — רוב השאילתות מתחילות ב"היכן נמצאת ישות זו כנושא/אובייקט" +2. **p** — מסנן נפוץ נוסף, "תן לי את כל `knows` הקשרים" +3. **otype** — מאפשר סינון לפי קשרים בעלי ערך URI לעומת קשרים בעלי ערך מילולי +4. **s, o, d** — עמודות שנותרו לשם ייחודיות +5. **dtype, lang** — מבדילים בין מילולים בעלי אותו ערך אך מטא-נתונים שונים (לדוגמה, `"thing"` לעומת `"thing"@en` לעומת `"thing"^^xsd:string`) + +### טבלה 2: quads_by_collection + +תומך בשאילתות ובמחיקות ברמת האוסף. מספק תצוגה של כל ה-quads השייכים לאוסף. נקרא כך כדי לשקף את דפוס השאילתה (חיפוש לפי אוסף). + +```sql +CREATE TABLE quads_by_collection ( + collection text, + d text, -- Dataset/graph of the quad + s text, -- Subject of the quad + p text, -- Predicate of the quad + o text, -- Object of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + dtype text, -- XSD datatype (when otype = 'L') + lang text, -- Language tag (when otype = 'L') + PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang) +); +``` + +מאוגדים לפי קבוצת נתונים תחילה, מה שמאפשר מחיקה ברמת אוסף או ברמת קבוצת נתונים. העמודות `otype`, `dtype` ו-`lang` כלולות במפתח האריגה כדי להבחין בין ערכים המילוליים עם אותו ערך אך עם מטא-נתונים מסוג שונים - ב-RDF, `"thing"`, `"thing"@en` ו-`"thing"^^xsd:string` הם ערכים שונים מבחינה סמנטית. + +## נתיב כתיבה + +עבור כל רביעייה נכנסת `(D, S, P, O)` בתוך אוסף `C`, כתבו **4 שורות** ל-`quads_by_entity` ו-**שורה אחת** ל-`quads_by_collection`. + +### דוגמה + +בהינתן הרביעייה באוסף `tenant1`: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: https://example.org/knows +Object: https://example.org/Bob +``` + +כתוב 4 שורות ל-`quads_by_entity`: + +| collection | entity | role | p | otype | s | o | d | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | + +כתוב שורה אחת ל-`quads_by_collection`: + +| collection | d | s | p | o | otype | dtype | lang | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | | + +### דוגמה מילולית + +עבור משולש תווית: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: http://www.w3.org/2000/01/rdf-schema#label +Object: "Alice Smith" (lang: en) +``` + +הקוד `otype` הוא `'L'`, `dtype` הוא `'xsd:string'`, ו-`lang` הוא `'en'`. הערך המילולי `"Alice Smith"` מאוחסן ב-`o`. נדרשות רק 3 שורות ב-`quads_by_entity` - שורה אינה נכתבת עבור הערך המילולי כישות, מכיוון שערכים מילוליים אינם ישויות שאפשר לשאול אותן באופן עצמאי. + +## תבניות שאילתה + +### כל 16 תבניות DSPO + +בטבלה למטה, "קידומת מושלמת" פירושה שהשאילתה משתמשת בקידומת רציפה של עמודי הקיבוץ. "סריקת מחיצה + סינון" פירושה ש-Cassandra קוראת חלק ממחיצה ומסננת בזיכרון - יעיל, אבל לא התאמה מדויקת לקידומת. + +| # | ידוע | ישות | קידומת קיבוץ | יעילות | +|---|---|---|---|---| +| 1 | D,S,P,O | entity=S, role='S', p=P | התאמה מלאה | קידומת מושלמת | +| 2 | D,S,P,? | entity=S, role='S', p=P | סינון על D | סריקת מחיצה + סינון | +| 3 | D,S,?,O | entity=S, role='S' | סינון על D, O | סריקת מחיצה + סינון | +| 4 | D,?,P,O | entity=O, role='O', p=P | סינון על D | סריקת מחיצה + סינון | +| 5 | ?,S,P,O | entity=S, role='S', p=P | סינון על O | סריקת מחיצה + סינון | +| 6 | D,S,?,? | entity=S, role='S' | סינון על D | סריקת מחיצה + סינון | +| 7 | D,?,P,? | entity=P, role='P' | סינון על D | סריקת מחיצה + סינון | +| 8 | D,?,?,O | entity=O, role='O' | סינון על D | סריקת מחיצה + סינון | +| 9 | ?,S,P,? | entity=S, role='S', p=P | — | **קידומת מושלמת** | +| 10 | ?,S,?,O | entity=S, role='S' | סינון על O | סריקת מחיצה + סינון | +| 11 | ?,?,P,O | entity=O, role='O', p=P | — | **קידומת מושלמת** | +| 12 | D,?,?,? | entity=D, role='G' | — | **קידומת מושלמת** | +| 13 | ?,S,?,? | entity=S, role='S' | — | **קידומת מושלמת** | +| 14 | ?,?,P,? | entity=P, role='P' | — | **קידומת מושלמת** | +| 15 | ?,?,?,O | entity=O, role='O' | — | **קידומת מושלמת** | +| 16 | ?,?,?,? | — | סריקה מלאה | חקירה בלבד | + +**תוצאה עיקרית**: 7 מתוך 15 התבניות הלא טריוויאליות הן התאמות מושלמות לקידומת קיבוץ. שמונה הנותרות הן קריאות מחיצה בודדות עם סינון בתוך המחיצה. כל שאילתה עם לפחות רכיב ידוע פוגעת במפתח המחיצה. + +התבנית 16 (?,?,?,?) אינה מתרחשת בפועל מכיוון שאוסף תמיד מצוין, מה שמצמצם אותה לתבנית 12. + +### דוגמאות נפוצות לשאילתות + +**כל דבר על ישות:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'; +``` + +**כל הקשרים יוצאים עבור ישות:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S'; +``` + +**תכונה ספציפית עבור ישות:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows'; +``` + +**תווית עבור ישות (שפה ספציפית):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label' +AND otype = 'L'; +``` + +לאחר מכן, במידת הצורך, סננו באמצעות `lang = 'en'` בצד האפליקציה. + +**רק קשרים בעלי ערך URI (קישורים בין ישויות לישויות):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U'; +``` + +**חיפוש הפוך — מה מצביע על ישות זו:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob' +AND role = 'O'; +``` + +## פתרון תוויות וחימום מטמון + +אחד היתרונות המשמעותיים ביותר של מודל המרכז את הישות הוא ש**פתרון תוויות הופך לתופעת לוואי חופשית**. + +במודל הרב-טבלאי המסורתי, שליפת תוויות דורשת שאילתות נפרדות: יש לשלוף משולשות, לזהות את כתובות ה-URI של הישויות בתוצאות, ולאחר מכן לשלוף `rdfs:label` עבור כל אחת. דפוס N+1 זה יקר. + +במודל המרכז את הישות, שאילתה של ישות מחזירה את כל ה-quads שלה - כולל התוויות, הסוגים ותכונות אחרות. כאשר האפליקציה שומרת תוצאות שאילתה במטמון, התוויות מחוממות מראש לפני שמישהו מבקש אותן. + +שני מצבי שימוש מאשרים שזה עובד היטב בפועל: + +**שאילתות המיועדות למשתמשים**: קבוצות תוצאות קטנות באופן טבעי, תוויות חיוניות. קריאות לישות מחממות את המטמון מראש. +**שאילתות AI/מערכיות**: קבוצות תוצאות גדולות עם מגבלות קשות. תוויות או שאינן נחוצות או נדרשות רק עבור תת-קבוצה מבוקרת של ישויות שכבר נמצאות במטמון. + +החשש התיאורטי של פתרון תוויות עבור קבוצות תוצאות גדולות (לדוגמה, 30,000 ישויות) מופחת על ידי התצפית המעשית שאף צרכן אנושי או AI לא מעבד שימושית כמות כזו של תוויות. מגבלות שאילתה ברמת האפליקציה מבטיחות שלחץ המטמון נשאר ניתן לניהול. + +## מחיצות רחבות ומימוש + +מימוש (הצהרות מסוג RDF-star על הצהרות) יוצר ישויות מרכזיות - לדוגמה, מסמך מקור התומך באלפי עובדות שחולצו. זה יכול ליצור מחיצות רחבות. + +גורמים מקלים: + +**מגבלות שאילתה ברמת האפליקציה**: כל שאילתות GraphRAG ושאילתות המיועדות למשתמשים מאכפות מגבלות קשות, כך שמחיצות רחבות לעולם אינן נסרקות במלואן בנתיב הקריאה החמה +**Cassandra מטפלת בקריאות חלקיות בצורה יעילה**: סריקת עמודת קיבוץ עם עצירה מוקדמת היא מהירה גם על מחיצות גדולות +**מחיקת אוסף** (הפעולה היחידה שעשויה לעבור על מחיצות מלאות) היא תהליך רקע מקובל + +## מחיקת אוסף + +מופעלת על ידי קריאת API, רצה ברקע (עקביות בסופו של דבר). + +1. קרא `quads_by_collection` עבור האוסף המיועד כדי לקבל את כל ה-quads +2. חלץ ישויות ייחודיות מה-quads (ערכי s, p, o, d) +3. עבור כל ישות ייחודית, מחק את המחיצה מ-`quads_by_entity` +4. מחק את השורות מ-`quads_by_collection` + +הטבלה `quads_by_collection` מספקת את האינדקס הדרוש כדי לאתר את כל מחיצות הישויות מבלי לסרוק את הטבלה כולה. מחיקות ברמת המחיצה יעילות מכיוון ש-`(collection, entity)` הוא מפתח המחיצה. + +## נתיב מעבר ממודל רב-טבלאי + +מודל המרכז את הישות יכול לדור בכפיפות למודל הרב-טבלאי הקיים במהלך המעבר: + +1. פרוס את הטבלאות `quads_by_entity` ו-`quads_by_collection` לצד הטבלאות הקיימות +2. כתוב כפול quads חדשים גם לטבלאות הישנות וגם לטבלאות החדשות +3. מלא נתונים קיימים לתוך הטבלאות החדשות +4. העבר נתיבי קריאה דפוס שאילתה בכל פעם +5. הפסק את פעולת הטבלאות הישנות לאחר שכל הקריאות עברו + +## סיכום + +| היבט | מסורתי (6 טבלאות) | מרכז ישות (2 טבלאות) | +|---|---|---| +| טבלאות | 7+ | 2 | +| כתיבות לכל quad | 6+ | 5 (4 נתונים + 1 מניפסט) | +| פתרון תוויות | מעברי נסיעה נפרדים | חימום מטמון חופשי | +| דפוסי שאילתה | 16 על פני 6 טבלאות | 16 על טבלה אחת | +| מורכבות סכימה | גבוהה | נמוכה | +| תקורה תפעולית | 6 טבלאות לכיול/תיקון | טבלת נתונים אחת | +| תמיכה במימוש | מורכבות נוספת | התאמה טבעית | +| סינון סוגי אובייקטים | לא זמין | ילידי (דרך קיבוץ otype) | +פלט חוזה (יש לעקוב בדיוק אחר הפורמט). diff --git a/docs/tech-specs/entity-centric-graph.hi.md b/docs/tech-specs/entity-centric-graph.hi.md new file mode 100644 index 00000000..8ece4e20 --- /dev/null +++ b/docs/tech-specs/entity-centric-graph.hi.md @@ -0,0 +1,261 @@ +# एंटिटी-सेंट्रिक नॉलेज ग्राफ स्टोरेज ऑन कैसेंड्रा + +## अवलोकन + +यह दस्तावेज़ अपाचे कैसेंड्रा पर आरडीएफ-शैली नॉलेज ग्राफ के लिए एक स्टोरेज मॉडल का वर्णन करता है। यह मॉडल एक **एंटिटी-सेंट्रिक** दृष्टिकोण का उपयोग करता है, जिसमें प्रत्येक एंटिटी उन सभी क्वाड के बारे में जानती है जिनमें वह भाग लेता है और वह जो भूमिका निभाता है। यह पारंपरिक मल्टी-टेबल एस.पी.ओ. क्रमपरिवर्तन दृष्टिकोण को केवल दो तालिकाओं से बदल देता है। + +## पृष्ठभूमि और प्रेरणा + +### पारंपरिक दृष्टिकोण + +कैसेंड्रा पर एक मानक आरडीएफ क्वाड स्टोर को क्वेरी पैटर्न को कवर करने के लिए कई डीनॉर्मलाइज़्ड तालिकाओं की आवश्यकता होती है - आमतौर पर 6 या अधिक टेबल जो विषय, विधेय, वस्तु और डेटासेट (एसपीओडी) के विभिन्न क्रमपरिवर्तनों का प्रतिनिधित्व करते हैं। प्रत्येक क्वाड को प्रत्येक तालिका में लिखा जाता है, जिसके परिणामस्वरूप महत्वपूर्ण राइट एम्प्लीफिकेशन, परिचालन ओवरहेड और स्कीमा जटिलता होती है। + +इसके अतिरिक्त, लेबल रिज़ॉल्यूशन (एंटिटीज के लिए मानव-पठनीय नामों को प्राप्त करना) के लिए अलग राउंड-ट्रिप क्वेरी की आवश्यकता होती है, जो एआई और ग्राफआरएजी उपयोग के मामलों में विशेष रूप से महंगी होती है, जहां एलएलएम संदर्भ के लिए लेबल आवश्यक हैं। + +### एंटिटी-सेंट्रिक अंतर्दृष्टि + +प्रत्येक क्वाड `(D, S, P, O)` में अधिकतम 4 एंटिटीज शामिल होती हैं। प्रत्येक एंटिटी की क्वाड में भागीदारी के लिए एक पंक्ति लिखकर, हम यह गारंटी देते हैं कि **किसी भी क्वेरी में कम से कम एक ज्ञात तत्व होगा, जो एक विभाजन कुंजी पर हिट करेगा।** यह एकल डेटा तालिका के साथ सभी 16 क्वेरी पैटर्न को कवर करता है। + +मुख्य लाभ: + +**2 टेबल** 7+ तालिकाओं के बजाय +**प्रति क्वाड 4 राइट** 6+ राइट के बजाय +**लेबल रिज़ॉल्यूशन मुफ्त में** - एक एंटिटी के लेबल उसके संबंधों के साथ स्थित होते हैं, जो स्वाभाविक रूप से एप्लिकेशन कैश को गर्म करते हैं +**सभी 16 क्वेरी पैटर्न** सिंगल-पार्टिशन रीड द्वारा परोसे जाते हैं +**सरल संचालन** - ट्यून करने, कंपैक्ट करने और रिपेयर करने के लिए एक डेटा टेबल + +## स्कीमा + +### टेबल 1: quads_by_entity + +प्राथमिक डेटा तालिका। प्रत्येक एंटिटी में एक विभाजन होता है जिसमें वह सभी क्वाड शामिल होते हैं जिनमें वह भाग लेता है। क्वेरी पैटर्न (एंटिटी द्वारा लुकअप) को दर्शाने के लिए नामित। + +```sql +CREATE TABLE quads_by_entity ( + collection text, -- Collection/tenant scope (always specified) + entity text, -- The entity this row is about + role text, -- 'S', 'P', 'O', 'G' — how this entity participates + p text, -- Predicate of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + s text, -- Subject of the quad + o text, -- Object of the quad + d text, -- Dataset/graph of the quad + dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string' + lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr' + PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang) +); +``` + +**विभाजन कुंजी (पार्टिशन की):** `(collection, entity)` — संग्रह के लिए निर्धारित, प्रत्येक इकाई के लिए एक विभाजन। + +**क्लस्टरिंग कॉलम क्रम का तर्क:** + +1. **भूमिका (role):** अधिकांश क्वेरी "यह इकाई विषय/वस्तु है" से शुरू होती हैं। +2. **p:** अगला सबसे आम फ़िल्टर, "मुझे सभी `knows` संबंध दिखाएं"। +3. **otype:** URI-मान वाले बनाम शाब्दिक-मान वाले संबंधों के आधार पर फ़िल्टर करने में सक्षम बनाता है। +4. **s, o, d:** विशिष्टता के लिए शेष कॉलम। +5. **dtype, lang:** समान मान वाले लेकिन अलग-अलग प्रकार के मेटाडेटा वाले शाब्दिकों को अलग करने के लिए (उदाहरण के लिए, `"thing"` बनाम `"thing"@en` बनाम `"thing"^^xsd:string`)। + +### तालिका 2: quads_by_collection + +संग्रह-स्तरीय क्वेरी और हटाने का समर्थन करता है। यह एक संग्रह से संबंधित सभी क्वाड का एक विवरण प्रदान करता है। इसे उस क्वेरी पैटर्न को दर्शाने के लिए नामित किया गया है (संग्रह द्वारा खोज)। + +```sql +CREATE TABLE quads_by_collection ( + collection text, + d text, -- Dataset/graph of the quad + s text, -- Subject of the quad + p text, -- Predicate of the quad + o text, -- Object of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + dtype text, -- XSD datatype (when otype = 'L') + lang text, -- Language tag (when otype = 'L') + PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang) +); +``` + +सबसे पहले डेटासेट के आधार पर समूहीकृत किया जाता है, जिससे संग्रह या डेटासेट स्तर पर हटाने की सुविधा मिलती है। `otype`, `dtype`, और `lang` कॉलम को समूहीकरण कुंजी में शामिल किया गया है ताकि समान मान वाले लिटरल को अलग किया जा सके, लेकिन अलग-अलग प्रकार के मेटाडेटा के साथ - RDF में, `"thing"`, `"thing"@en`, और `"thing"^^xsd:string` अर्थपूर्ण रूप से भिन्न मान हैं। + +## लेखन पथ + +प्रत्येक आने वाले क्वाड `(D, S, P, O)` के लिए, जो संग्रह `C` के भीतर है, `quads_by_entity` में **4 पंक्तियाँ** और `quads_by_collection` में **1 पंक्ति** लिखें। + +### उदाहरण + +संग्रह `tenant1` में क्वाड दिया गया है: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: https://example.org/knows +Object: https://example.org/Bob +``` + +`quads_by_entity` में 4 पंक्तियाँ लिखें: + +| संग्रह | इकाई | भूमिका | p | otype | s | o | d | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | + +`quads_by_collection` में 1 पंक्ति लिखें: + +| संग्रह | d | s | p | o | otype | dtype | lang | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | | + +### शाब्दिक उदाहरण + +एक लेबल ट्रिपल के लिए: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: http://www.w3.org/2000/01/rdf-schema#label +Object: "Alice Smith" (lang: en) +``` + +`otype` का मान `'L'` है, `dtype` का मान `'xsd:string'` है, और `lang` का मान `'en'` है। शाब्दिक मान `"Alice Smith"` को `o` में संग्रहीत किया जाता है। `quads_by_entity` में केवल 3 पंक्तियों की आवश्यकता होती है - शाब्दिक को इकाई के रूप में लिखने के लिए कोई पंक्ति नहीं लिखी जाती है, क्योंकि शाब्दिक स्वतंत्र रूप से क्वेरी करने योग्य इकाइयाँ नहीं हैं। + +## क्वेरी पैटर्न + +### सभी 16 डीएसपीओ पैटर्न + +नीचे दी गई तालिका में, "परिपूर्ण उपसर्ग" का अर्थ है कि क्वेरी क्लस्टरिंग कॉलम के एक निरंतर उपसर्ग का उपयोग करती है। "विभाजन स्कैन + फ़िल्टर" का अर्थ है कि कैसेंड्रा एक विभाजन के एक स्लाइस को पढ़ता है और मेमोरी में फ़िल्टर करता है - यह कुशल है, लेकिन यह एक शुद्ध उपसर्ग मिलान नहीं है। + +| # | ज्ञात | लुकअप इकाई | क्लस्टरिंग उपसर्ग | दक्षता | +|---|---|---|---|---| +| 1 | डी, एस, पी, ओ | इकाई=एस, भूमिका='एस', पी=पी | पूर्ण मिलान | परिपूर्ण उपसर्ग | +| 2 | डी, एस, पी, ? | इकाई=एस, भूमिका='एस', पी=पी | डी पर फ़िल्टर | विभाजन स्कैन + फ़िल्टर | +| 3 | डी, एस, ?, ओ | इकाई=एस, भूमिका='एस' | डी, ओ पर फ़िल्टर | विभाजन स्कैन + फ़िल्टर | +| 4 | डी, ?, पी, ओ | इकाई=ओ, भूमिका='ओ', पी=पी | डी पर फ़िल्टर | विभाजन स्कैन + फ़िल्टर | +| 5 | ?, एस, पी, ओ | इकाई=एस, भूमिका='एस', पी=पी | ओ पर फ़िल्टर | विभाजन स्कैन + फ़िल्टर | +| 6 | डी, एस, ?, ? | इकाई=एस, भूमिका='एस' | डी पर फ़िल्टर | विभाजन स्कैन + फ़िल्टर | +| 7 | डी, ?, पी, ? | इकाई=पी, भूमिका='पी' | डी पर फ़िल्टर | विभाजन स्कैन + फ़िल्टर | +| 8 | डी, ?, ?, ओ | इकाई=ओ, भूमिका='ओ' | डी पर फ़िल्टर | विभाजन स्कैन + फ़िल्टर | +| 9 | ?, एस, पी, ? | इकाई=एस, भूमिका='एस', पी=पी | — | **परिपूर्ण उपसर्ग** | +| 10 | ?, एस, ?, ओ | इकाई=एस, भूमिका='एस' | ओ पर फ़िल्टर | विभाजन स्कैन + फ़िल्टर | +| 11 | ?, ?, पी, ओ | इकाई=ओ, भूमिका='ओ', पी=पी | — | **परिपूर्ण उपसर्ग** | +| 12 | डी, ?, ?, ? | इकाई=डी, भूमिका='जी' | — | **परिपूर्ण उपसर्ग** | +| 13 | ?, एस, ?, ? | इकाई=एस, भूमिका='एस' | — | **परिपूर्ण उपसर्ग** | +| 14 | ?, ?, पी, ? | इकाई=पी, भूमिका='पी' | — | **परिपूर्ण उपसर्ग** | +| 15 | ?, ?, ?, ओ | इकाई=ओ, भूमिका='ओ' | — | **परिपूर्ण उपसर्ग** | +| 16 | ?, ?, ?, ? | — | पूर्ण स्कैन | केवल अन्वेषण | + +**मुख्य परिणाम**: 15 गैर-तुच्छ पैटर्नों में से 7 परिपूर्ण क्लस्टरिंग उपसर्ग हिट हैं। शेष 8 एकल-विभाजन रीड हैं जिनमें इन-पार्टिशन फ़िल्टरिंग होती है। प्रत्येक क्वेरी जिसमें कम से कम एक ज्ञात तत्व होता है, वह एक विभाजन कुंजी को हिट करती है। + +पैटर्न 16 (?, ?, ?, ?) व्यवहार में नहीं होता है क्योंकि संग्रह हमेशा निर्दिष्ट होता है, जिससे यह पैटर्न 12 में कम हो जाता है। + +### सामान्य क्वेरी उदाहरण + +**किसी इकाई के बारे में सब कुछ:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'; +``` + +**किसी इकाई के लिए सभी बाहरी संबंध:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S'; +``` + +**किसी इकाई के लिए विशिष्ट विधेय:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows'; +``` + +**किसी इकाई के लिए लेबल (विशिष्ट भाषा):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label' +AND otype = 'L'; +``` + +फिर, यदि आवश्यक हो, तो `lang = 'en'` एप्लिकेशन-साइड पर फ़िल्टर करें। + +**केवल URI-मान वाले संबंध (इकाई-से-इकाई लिंक):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U'; +``` + +**रिवर्स लुकअप - यह इकाई किससे जुड़ी है:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob' +AND role = 'O'; +``` + +## लेबल रिज़ॉल्यूशन और कैश वार्मिंग + +एंटिटी-सेंट्रिक मॉडल के सबसे महत्वपूर्ण लाभों में से एक यह है कि **लेबल रिज़ॉल्यूशन एक मुफ्त साइड इफ़ेक्ट बन जाता है।** + +पारंपरिक मल्टी-टेबल मॉडल में, लेबल प्राप्त करने के लिए अलग-अलग राउंड-ट्रिप क्वेरी की आवश्यकता होती है: ट्रिपल प्राप्त करें, परिणामों में एंटिटी यूआरआई की पहचान करें, फिर प्रत्येक के लिए `rdfs:label` प्राप्त करें। यह N+1 पैटर्न महंगा है। + +एंटिटी-सेंट्रिक मॉडल में, किसी एंटिटी को क्वेरी करने पर, यह उसके सभी क्वाड लौटाता है - जिसमें उसके लेबल, प्रकार और अन्य गुण शामिल हैं। जब एप्लिकेशन क्वेरी परिणामों को कैश करता है, तो लेबल किसी भी चीज़ के लिए अनुरोध करने से पहले ही प्री-वार्म हो जाते हैं। + +दो उपयोग परिदृश्य इस बात की पुष्टि करते हैं कि यह व्यवहार में अच्छी तरह से काम करता है: + +**मानव-सामना करने वाली क्वेरी:** स्वाभाविक रूप से छोटे परिणाम सेट, लेबल आवश्यक। एंटिटी रीड कैश को प्री-वार्म करते हैं। +**एआई/बल्क क्वेरी:** बड़े परिणाम सेट जिनमें सख्त सीमाएं होती हैं। लेबल या तो अनावश्यक होते हैं या केवल उन एंटिटीज के एक क्यूरेटेड सबसेट के लिए आवश्यक होते हैं जो पहले से ही कैश में हैं। + +30,000 एंटिटीज जैसे विशाल परिणाम सेट के लिए लेबल को हल करने की सैद्धांतिक चिंता को इस व्यावहारिक अवलोकन द्वारा कम किया जाता है कि कोई भी मानव या एआई उपभोक्ता उन सभी लेबलों को उपयोगी रूप से संसाधित नहीं करता है। एप्लिकेशन-स्तरीय क्वेरी सीमाएं यह सुनिश्चित करती हैं कि कैश दबाव प्रबंधनीय रहे। + +## वाइड पार्टिशन्स और रीफिकेशन + +रीफिकेशन (आरडीएफ-स्टार शैली के स्टेटमेंट स्टेटमेंट के बारे में) हब एंटिटीज बनाते हैं - उदाहरण के लिए, एक स्रोत दस्तावेज़ जो निकाले गए हजारों तथ्यों का समर्थन करता है। इससे वाइड पार्टिशन्स बन सकते हैं। + +कम करने वाले कारक: + +**एप्लिकेशन-स्तरीय क्वेरी सीमाएं:** सभी GraphRAG और मानव-सामना करने वाली क्वेरी सख्त सीमाओं को लागू करती हैं, इसलिए हॉट रीड पाथ पर वाइड पार्टिशन्स को कभी भी पूरी तरह से स्कैन नहीं किया जाता है। +**कैसेंड्रा आंशिक रीड को कुशलता से संभालता है:** एक क्लस्टरिंग कॉलम स्कैन जिसमें शुरुआती स्टॉप हो, वह बड़े पार्टिशन्स पर भी तेज़ होता है। +**कलेक्शन डिलीशन** (केवल वह ऑपरेशन जो पूरे पार्टिशन्स को पार कर सकता है) एक स्वीकृत पृष्ठभूमि प्रक्रिया है। + +## कलेक्शन डिलीशन + +एपीआई कॉल द्वारा ट्रिगर किया गया, पृष्ठभूमि में चलता है (अंततः सुसंगत)। + +1. लक्ष्य कलेक्शन के लिए `quads_by_collection` पढ़ें ताकि सभी क्वाड प्राप्त हो सकें। +2. क्वाड से अद्वितीय एंटिटीज निकालें (s, p, o, d मान)। +3. प्रत्येक अद्वितीय एंटिटी के लिए, `quads_by_entity` से पार्टीशन को हटाएं। +4. `quads_by_collection` से पंक्तियों को हटाएं। + +`quads_by_collection` टेबल वह इंडेक्स प्रदान करता है जिसकी आवश्यकता सभी एंटिटी पार्टिशन्स को खोजने के लिए होती है बिना पूरे टेबल स्कैन के। पार्टीशन-स्तरीय डिलीट कुशल हैं क्योंकि `(collection, entity)` पार्टीशन कुंजी है। + +## मल्टी-टेबल मॉडल से माइग्रेशन पाथ + +एंटिटी-सेंट्रिक मॉडल मौजूदा मल्टी-टेबल मॉडल के साथ माइग्रेशन के दौरान सह-अस्तित्व में रह सकता है: + +1. मौजूदा टेबल के साथ `quads_by_entity` और `quads_by_collection` टेबल तैनात करें। +2. नए और पुराने दोनों टेबल में नए क्वाड को डुअल-राइट करें। +3. मौजूदा डेटा को नए टेबल में बैकफिल करें। +4. एक क्वेरी पैटर्न को एक बार में माइग्रेट करें। +5. सभी रीड माइग्रेट होने के बाद पुराने टेबल को डीकमीशन करें। + +## सारांश + +| पहलू | पारंपरिक (6-टेबल) | एंटिटी-सेंट्रिक (2-टेबल) | +|---|---|---| +| टेबल | 7+ | 2 | +| क्वाड प्रति राइट | 6+ | 5 (4 डेटा + 1 मैनिफेस्ट) | +| लेबल रिज़ॉल्यूशन | अलग राउंड ट्रिप | कैश वार्मिंग के माध्यम से मुफ्त | +| क्वेरी पैटर्न | 6 टेबल में 16 | 1 टेबल में 16 | +| स्कीमा जटिलता | उच्च | कम | +| परिचालन ओवरहेड | ट्यून/मरम्मत के लिए 6 टेबल | 1 डेटा टेबल | +| रीफिकेशन सपोर्ट | अतिरिक्त जटिलता | प्राकृतिक फिट | +| ऑब्जेक्ट टाइप फ़िल्टरिंग | उपलब्ध नहीं | देशी (otype क्लस्टरिंग के माध्यम से) | + diff --git a/docs/tech-specs/entity-centric-graph.pt.md b/docs/tech-specs/entity-centric-graph.pt.md new file mode 100644 index 00000000..777062d9 --- /dev/null +++ b/docs/tech-specs/entity-centric-graph.pt.md @@ -0,0 +1,261 @@ +# Armazenamento de Grafos de Conhecimento Centrados em Entidades no Cassandra + +## Visão Geral + +Este documento descreve um modelo de armazenamento para grafos de conhecimento no estilo RDF no Apache Cassandra. O modelo usa uma abordagem **centrada em entidades**, onde cada entidade conhece cada quádrupla em que participa e o papel que desempenha. Isso substitui uma abordagem tradicional de permutação SPO em várias tabelas por apenas duas tabelas. + +## Contexto e Motivação + +### A Abordagem Tradicional + +Um armazenamento RDF padrão no Cassandra requer várias tabelas desnormalizadas para cobrir padrões de consulta — normalmente 6 ou mais tabelas representando diferentes permutações de Sujeito, Predicado, Objeto e Conjunto de Dados (SPOD). Cada quádrupla é escrita em todas as tabelas, resultando em uma amplificação de escrita significativa, sobrecarga operacional e complexidade do esquema. + +Além disso, a resolução de rótulos (busca de nomes legíveis para humanos para entidades) requer consultas separadas de ida e volta, o que é particularmente caro em casos de uso de IA e GraphRAG, onde os rótulos são essenciais para o contexto do LLM. + +### A Perspectiva Centrada na Entidade + +Cada quádrupla `(D, S, P, O)` envolve até 4 entidades. Ao escrever uma linha para a participação de cada entidade na quádrupla, garantimos que **qualquer consulta com pelo menos um elemento conhecido atingirá uma chave de partição**. Isso cobre todos os 16 padrões de consulta com uma única tabela de dados. + +Benefícios principais: + +**2 tabelas** em vez de 7+ +**4 gravações por quádrupla** em vez de 6+ +**Resolução de rótulos gratuita** — os rótulos de uma entidade estão localizados com seus relacionamentos, aquecendo naturalmente o cache da aplicação +**Todos os 16 padrões de consulta** atendidos por leituras de partição única +**Operações mais simples** — uma única tabela de dados para ajustar, compactar e reparar + +## Esquema + +### Tabela 1: quads_by_entity + +A tabela de dados primária. Cada entidade tem uma partição contendo todas as quádruplas em que participa. Nomeada para refletir o padrão de consulta (busca por entidade). +Saída do contrato (deve seguir exatamente o formato abaixo). +```sql +CREATE TABLE quads_by_entity ( + collection text, -- Collection/tenant scope (always specified) + entity text, -- The entity this row is about + role text, -- 'S', 'P', 'O', 'G' — how this entity participates + p text, -- Predicate of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + s text, -- Subject of the quad + o text, -- Object of the quad + d text, -- Dataset/graph of the quad + dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string' + lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr' + PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang) +); +``` + +**Chave de partição**: `(collection, entity)` — restrita à coleção, uma partição por entidade. + +**Justificativa para a ordem das colunas de agrupamento**: + +1. **role** — a maioria das consultas começa com "onde esta entidade é um sujeito/objeto" +2. **p** — próximo filtro mais comum, "me dê todas as relações `knows`" +3. **otype** — permite filtrar por relações com valor URI versus relações com valor literal +4. **s, o, d** — colunas restantes para garantir a unicidade +5. **dtype, lang** — distingue literais com o mesmo valor, mas com metadados de tipo diferentes (por exemplo, `"thing"` vs `"thing"@en` vs `"thing"^^xsd:string`) + +### Tabela 2: quads_by_collection + +Suporta consultas e exclusões no nível da coleção. Fornece um manifesto de todos os quads pertencentes a uma coleção. Nomeado para refletir o padrão de consulta (pesquisa por coleção). + +```sql +CREATE TABLE quads_by_collection ( + collection text, + d text, -- Dataset/graph of the quad + s text, -- Subject of the quad + p text, -- Predicate of the quad + o text, -- Object of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + dtype text, -- XSD datatype (when otype = 'L') + lang text, -- Language tag (when otype = 'L') + PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang) +); +``` + +Agrupados primeiro por conjunto de dados, permitindo a exclusão em nível de coleção ou de conjunto de dados. As colunas `otype`, `dtype` e `lang` estão incluídas na chave de agrupamento para distinguir literais com o mesmo valor, mas com metadados de tipo diferentes — em RDF, `"thing"`, `"thing"@en` e `"thing"^^xsd:string` são valores semanticamente distintos. + +## Caminho de Escrita + +Para cada quádruplo de entrada `(D, S, P, O)` dentro de uma coleção `C`, escreva **4 linhas** em `quads_by_entity` e **1 linha** em `quads_by_collection`. + +### Exemplo + +Dado o quádruplo na coleção `tenant1`: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: https://example.org/knows +Object: https://example.org/Bob +``` + +Escreva 4 linhas para `quads_by_entity`: + +| collection | entity | role | p | otype | s | o | d | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | + +Escreva 1 linha para `quads_by_collection`: + +| collection | d | s | p | o | otype | dtype | lang | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | | + +### Exemplo Literal + +Para uma tripla de rótulo: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: http://www.w3.org/2000/01/rdf-schema#label +Object: "Alice Smith" (lang: en) +``` + +O `otype` é `'L'`, `dtype` é `'xsd:string'`, e `lang` é `'en'`. O valor literal `"Alice Smith"` é armazenado em `o`. Apenas 3 linhas são necessárias em `quads_by_entity` — nenhuma linha é escrita para o literal como entidade, pois os literais não são entidades consultáveis independentes. + +## Padrões de Consulta + +### Todos os 16 Padrões DSPO + +Na tabela abaixo, "Prefixo perfeito" significa que a consulta usa um prefixo contíguo das colunas de agrupamento. "Leitura de partição + filtro" significa que o Cassandra lê uma fatia de uma partição e filtra na memória — ainda eficiente, mas não uma correspondência de prefixo pura. + +| # | Conhecido | Consulta de entidade | Prefixo de agrupamento | Eficiência | +|---|---|---|---|---| +| 1 | D,S,P,O | entidade=S, role='S', p=P | Correspondência completa | Prefixo perfeito | +| 2 | D,S,P,? | entidade=S, role='S', p=P | Filtro em D | Leitura de partição + filtro | +| 3 | D,S,?,O | entidade=S, role='S' | Filtro em D, O | Leitura de partição + filtro | +| 4 | D,?,P,O | entidade=O, role='O', p=P | Filtro em D | Leitura de partição + filtro | +| 5 | ?,S,P,O | entidade=S, role='S', p=P | Filtro em O | Leitura de partição + filtro | +| 6 | D,S,?,? | entidade=S, role='S' | Filtro em D | Leitura de partição + filtro | +| 7 | D,?,P,? | entidade=P, role='P' | Filtro em D | Leitura de partição + filtro | +| 8 | D,?,?,O | entidade=O, role='O' | Filtro em D | Leitura de partição + filtro | +| 9 | ?,S,P,? | entidade=S, role='S', p=P | — | **Prefixo perfeito** | +| 10 | ?,S,?,O | entidade=S, role='S' | Filtro em O | Leitura de partição + filtro | +| 11 | ?,?,P,O | entidade=O, role='O', p=P | — | **Prefixo perfeito** | +| 12 | D,?,?,? | entidade=D, role='G' | — | **Prefixo perfeito** | +| 13 | ?,S,?,? | entidade=S, role='S' | — | **Prefixo perfeito** | +| 14 | ?,?,P,? | entidade=P, role='P' | — | **Prefixo perfeito** | +| 15 | ?,?,?,O | entidade=O, role='O' | — | **Prefixo perfeito** | +| 16 | ?,?,?,? | — | Leitura completa | Apenas exploração | + +**Resultado chave**: 7 dos 15 padrões não triviais são correspondências perfeitas de prefixo de agrupamento. Os 8 restantes são leituras de partição única com filtragem dentro da partição. Cada consulta com pelo menos um elemento conhecido atinge uma chave de partição. + +O padrão 16 (?,?,?,?) não ocorre na prática, pois a coleção é sempre especificada, reduzindo-o ao padrão 12. + +### Exemplos Comuns de Consulta + +**Tudo sobre uma entidade:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'; +``` + +**Todos os relacionamentos de saída para uma entidade:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S'; +``` + +**Predicado específico para uma entidade:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows'; +``` + +**Rótulo para uma entidade (idioma específico):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label' +AND otype = 'L'; +``` + +Em seguida, filtre por aplicação no lado do cliente, se necessário, usando `lang = 'en'`. + +**Apenas relacionamentos com valores URI (links de entidade para entidade):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U'; +``` + +**Pesquisa reversa — o que aponta para esta entidade:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob' +AND role = 'O'; +``` + +## Resolução de Rótulos e Aquecimento do Cache + +Uma das vantagens mais significativas do modelo centrado em entidades é que **a resolução de rótulos se torna um efeito colateral gratuito**. + +No modelo tradicional de várias tabelas, buscar rótulos requer consultas separadas: recuperar triplas, identificar URIs de entidades nos resultados e, em seguida, buscar `rdfs:label` para cada uma. Esse padrão N+1 é caro. + +No modelo centrado em entidades, consultar uma entidade retorna **todos** os seus quadros — incluindo seus rótulos, tipos e outras propriedades. Quando o aplicativo armazena em cache os resultados das consultas, os rótulos são pré-aquecidos antes que qualquer coisa os solicite. + +Dois regimes de uso confirmam que isso funciona bem na prática: + +**Consultas voltadas para o usuário**: conjuntos de resultados naturalmente pequenos, rótulos essenciais. As leituras de entidades pré-aquecem o cache. +**Consultas de IA/em lote**: conjuntos de resultados grandes com limites rígidos. Os rótulos são desnecessários ou necessários apenas para um subconjunto selecionado de entidades que já estão no cache. + +A preocupação teórica de resolver rótulos para conjuntos de resultados enormes (por exemplo, 30.000 entidades) é atenuada pela observação prática de que nenhum usuário humano ou de IA processa tantos rótulos de forma útil. Os limites de consulta no nível da aplicação garantem que a pressão do cache permaneça gerenciável. + +## Partições Largas e Reificação + +A reificação (declarações RDF-star sobre declarações) cria entidades de hub — por exemplo, um documento de origem que suporta milhares de fatos extraídos. Isso pode produzir partições largas. + +Fatores atenuantes: + +**Limites de consulta no nível da aplicação**: todas as consultas do GraphRAG e voltadas para o usuário impõem limites rígidos, portanto, as partições largas nunca são totalmente examinadas no caminho de leitura quente. +**O Cassandra lida com leituras parciais de forma eficiente**: uma varredura de coluna de agrupamento com uma parada antecipada é rápida, mesmo em partições grandes. +**Exclusão de coleções** (a única operação que pode percorrer partições completas) é um processo de segundo plano aceitável. + +## Exclusão de Coleções + +Acionada por chamada de API, é executada em segundo plano (consistência eventual). + +1. Leia `quads_by_collection` para a coleção de destino para obter todos os quadros. +2. Extraia entidades exclusivas das quadros (valores s, p, o, d). +3. Para cada entidade exclusiva, exclua a partição de `quads_by_entity`. +4. Exclua as linhas de `quads_by_collection`. + +A tabela `quads_by_collection` fornece o índice necessário para localizar todas as partições de entidade sem uma varredura completa da tabela. As exclusões em nível de partição são eficientes porque `(collection, entity)` é a chave da partição. + +## Caminho de Migração do Modelo de Múltiplas Tabelas + +O modelo centrado em entidades pode coexistir com o modelo de múltiplas tabelas existente durante a migração: + +1. Implante as tabelas `quads_by_entity` e `quads_by_collection` junto com as tabelas existentes. +2. Escreva em duplicata novas quadros para ambas as tabelas antigas e novas. +3. Preencha os dados existentes nas novas tabelas. +4. Migre os caminhos de leitura um padrão de consulta por vez. +5. Desative as tabelas antigas assim que todos os caminhos de leitura forem migrados. + +## Resumo + +| Aspecto | Tradicional (6 tabelas) | Centrado em entidade (2 tabelas) | +|---|---|---| +| Tabelas | 7+ | 2 | +| Escritas por quadro | 6+ | 5 (4 dados + 1 manifesto) | +| Resolução de rótulos | Consultas separadas | Gratuito via aquecimento do cache | +| Padrões de consulta | 16 em 6 tabelas | 16 em 1 tabela | +| Complexidade do esquema | Alta | Baixa | +| Sobrecarga operacional | 6 tabelas para ajustar/reparar | 1 tabela de dados | +| Suporte de reificação | Complexidade adicional | Adequação natural | +| Filtragem de tipo de objeto | Não disponível | Nativo (via agrupamento de otype) | +Saída do contrato (deve seguir exatamente o formato abaixo). diff --git a/docs/tech-specs/entity-centric-graph.ru.md b/docs/tech-specs/entity-centric-graph.ru.md new file mode 100644 index 00000000..85efae9b --- /dev/null +++ b/docs/tech-specs/entity-centric-graph.ru.md @@ -0,0 +1,261 @@ +# Хранение графов знаний, ориентированных на сущности, в Cassandra + +## Обзор + +Этот документ описывает модель хранения графов знаний в стиле RDF в Apache Cassandra. Модель использует подход, ориентированный на сущности, при котором каждая сущность знает о каждой квадрупле, в которой она участвует, и о роли, которую она играет. Это заменяет традиционный подход с использованием нескольких таблиц и различных перестановок SPO (Subject, Predicate, Object) всего двумя таблицами. + +## Предыстория и мотивация + +### Традиционный подход + +Стандартное хранилище квадруплов RDF в Cassandra требует нескольких денормализованных таблиц для охвата шаблонов запросов — обычно 6 или более таблиц, представляющих различные перестановки Subject, Predicate, Object и Dataset (SPOD). Каждый квадруплет записывается в каждую таблицу, что приводит к значительному увеличению количества операций записи, оперативным издержкам и сложности схемы. + +Кроме того, разрешение меток (получение удобочитаемых имен для сущностей) требует отдельных запросов, что особенно дорого в сценариях использования AI и GraphRAG, где метки необходимы для контекста LLM. + +### Инсайт, ориентированный на сущности + +Каждый квадруплет `(D, S, P, O)` включает до 4 сущностей. Записывая строку для участия каждой сущности в квадруплете, мы гарантируем, что **любой запрос, содержащий хотя бы один известный элемент, попадет в первичный ключ**. Это охватывает все 16 шаблонов запросов с помощью одной таблицы данных. + +Основные преимущества: + +**2 таблицы** вместо 7+ +**4 записи на квадруплет** вместо 6+ +**Разрешение меток бесплатно** — метки сущности находятся рядом с ее отношениями, что естественным образом подогревает кэш приложения. +**Все 16 шаблонов запросов** обслуживаются с помощью чтения из одной секции. +**Более простые операции** — одна таблица данных для настройки, уплотнения и восстановления. + +## Схема + +### Таблица 1: quads_by_entity + +Основная таблица данных. Каждая сущность имеет секцию, содержащую все квадруплеты, в которых она участвует. Названа в соответствии с шаблоном запроса (поиск по сущности). + +```sql +CREATE TABLE quads_by_entity ( + collection text, -- Collection/tenant scope (always specified) + entity text, -- The entity this row is about + role text, -- 'S', 'P', 'O', 'G' — how this entity participates + p text, -- Predicate of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + s text, -- Subject of the quad + o text, -- Object of the quad + d text, -- Dataset/graph of the quad + dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string' + lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr' + PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang) +); +``` + +**Ключ секции (Partition key)**: `(collection, entity)` — ограничен областью действия коллекции, одна секция на сущность. + +**Обоснование порядка столбцов кластеризации**: + +1. **role** — большинство запросов начинаются с "где эта сущность является субъектом/объектом" +2. **p** — следующий по частоте фильтр, "верните все `knows` отношения" +3. **otype** — позволяет фильтровать по отношениям со значениями URI по сравнению с литеральными значениями +4. **s, o, d** — оставшиеся столбцы для обеспечения уникальности +5. **dtype, lang** — различают литералы с одинаковым значением, но с разными метаданными типа (например, `"thing"` vs `"thing"@en` vs `"thing"^^xsd:string`) + +### Таблица 2: quads_by_collection + +Поддерживает запросы и удаление на уровне коллекции. Предоставляет список всех квадруплетов, принадлежащих коллекции. Название отражает шаблон запроса (поиск по коллекции). + +```sql +CREATE TABLE quads_by_collection ( + collection text, + d text, -- Dataset/graph of the quad + s text, -- Subject of the quad + p text, -- Predicate of the quad + o text, -- Object of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + dtype text, -- XSD datatype (when otype = 'L') + lang text, -- Language tag (when otype = 'L') + PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang) +); +``` + +Группировка сначала по набору данных, что позволяет удалять данные как на уровне коллекции, так и на уровне набора данных. Столбцы `otype`, `dtype` и `lang` включены в ключ группировки для различения литералов с одинаковым значением, но с разными метаданными типа — в RDF, `"thing"`, `"thing"@en` и `"thing"^^xsd:string` являются семантически различными значениями. + +## Путь записи + +Для каждой входящей квадрупли `(D, S, P, O)` в коллекции `C`, записывайте **4 строки** в `quads_by_entity` и **1 строку** в `quads_by_collection`. + +### Пример + +Для квадрупли в коллекции `tenant1`: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: https://example.org/knows +Object: https://example.org/Bob +``` + +Запишите 4 строки в `quads_by_entity`: + +| collection | entity | role | p | otype | s | o | d | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | + +Запишите 1 строку в `quads_by_collection`: + +| collection | d | s | p | o | otype | dtype | lang | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | | + +### Пример с буквальным текстом + +Для тройки меток: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: http://www.w3.org/2000/01/rdf-schema#label +Object: "Alice Smith" (lang: en) +``` + +`otype` — это `'L'`, `dtype` — это `'xsd:string'`, а `lang` — это `'en'`. Литеральное значение `"Alice Smith"` хранится в `o`. В `quads_by_entity` требуется всего 3 строки — строка для литерала как сущности не записывается, поскольку литералы не являются независимыми сущностями, к которым можно обращаться. + +## Шаблоны запросов + +### Все 16 шаблонов DSPO + +В таблице ниже "Идеальный префикс" означает, что запрос использует непрерывный префикс столбцов кластеризации. "Сканирование раздела + фильтрация" означает, что Cassandra считывает часть одного раздела и фильтрует в памяти — это эффективно, но не является чистым совпадением префикса. + +| # | Известно | Поиск сущности | Префикс кластеризации | Эффективность | +|---|---|---|---|---| +| 1 | D,S,P,O | entity=S, role='S', p=P | Полное совпадение | Идеальный префикс | +| 2 | D,S,P,? | entity=S, role='S', p=P | Фильтрация по D | Сканирование раздела + фильтрация | +| 3 | D,S,?,O | entity=S, role='S' | Фильтрация по D, O | Сканирование раздела + фильтрация | +| 4 | D,?,P,O | entity=O, role='O', p=P | Фильтрация по D | Сканирование раздела + фильтрация | +| 5 | ?,S,P,O | entity=S, role='S', p=P | Фильтрация по O | Сканирование раздела + фильтрация | +| 6 | D,S,?,? | entity=S, role='S' | Фильтрация по D | Сканирование раздела + фильтрация | +| 7 | D,?,P,? | entity=P, role='P' | Фильтрация по D | Сканирование раздела + фильтрация | +| 8 | D,?,?,O | entity=O, role='O' | Фильтрация по D | Сканирование раздела + фильтрация | +| 9 | ?,S,P,? | entity=S, role='S', p=P | — | **Идеальный префикс** | +| 10 | ?,S,?,O | entity=S, role='S' | Фильтрация по O | Сканирование раздела + фильтрация | +| 11 | ?,?,P,O | entity=O, role='O', p=P | — | **Идеальный префикс** | +| 12 | D,?,?,? | entity=D, role='G' | — | **Идеальный префикс** | +| 13 | ?,S,?,? | entity=S, role='S' | — | **Идеальный префикс** | +| 14 | ?,?,P,? | entity=P, role='P' | — | **Идеальный префикс** | +| 15 | ?,?,?,O | entity=O, role='O' | — | **Идеальный префикс** | +| 16 | ?,?,?,? | — | Полное сканирование | Только исследование | + +**Ключевой результат**: 7 из 15 нетривиальных шаблонов являются идеальными совпадениями префикса кластеризации. Оставшиеся 8 — это чтение одного раздела с фильтрацией внутри раздела. Каждый запрос, содержащий хотя бы один известный элемент, соответствует ключу раздела. + +Шаблон 16 (?,?,?,?) не встречается на практике, поскольку коллекция всегда указана, что сводит его к шаблону 12. + +### Примеры распространенных запросов + +**Вся информация об сущности:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'; +``` + +**Все исходящие связи для сущности:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S'; +``` + +**Конкретный предикат для сущности:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows'; +``` + +**Метка для сущности (на конкретном языке):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label' +AND otype = 'L'; +``` + +Затем, при необходимости, выполните фильтрацию на стороне приложения с использованием `lang = 'en'`. + +**Только связи, имеющие значение URI (ссылки между сущностями):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U'; +``` + +**Обратный поиск — что указывает на эту сущность:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob' +AND role = 'O'; +``` + +## Разрешение меток и предварительная загрузка кэша + +Одним из наиболее значительных преимуществ модели, ориентированной на сущности, является то, что **разрешение меток становится побочным эффектом**. + +В традиционной многотабличной модели получение меток требует отдельных запросов: извлечение троек, определение URI сущностей в результатах, а затем получение `rdfs:label` для каждого. Этот шаблон N+1 дорог. + +В модели, ориентированной на сущности, запрос сущности возвращает **все** ее квадруплеты, включая ее метки, типы и другие свойства. Когда приложение кэширует результаты запросов, метки предварительно загружаются в кэш до того, как кто-либо запросит их. + +Два режима использования подтверждают, что это хорошо работает на практике: + +**Запросы, предназначенные для пользователей**: обычно небольшие наборы результатов, метки необходимы. Чтение сущностей предварительно загружает кэш. +**Запросы для ИИ/пакетной обработки**: большие наборы результатов с жесткими ограничениями. Метки либо не нужны, либо необходимы только для курированного подмножества сущностей, которые уже находятся в кэше. + +Теоретическое опасение по поводу разрешения меток для огромных наборов результатов (например, 30 000 сущностей) нивелируется практическим наблюдением, что ни один пользователь или ИИ не обрабатывает такое большое количество меток. Ограничения на запросы на уровне приложения обеспечивают, чтобы нагрузка на кэш оставалась управляемой. + +## Широкие разделы и реификация + +Реификация (утверждения RDF-star об утверждениях) создает центральные сущности, например, документ-источник, который поддерживает тысячи извлеченных фактов. Это может привести к широким разделам. + +Факторы, смягчающие ситуацию: + +**Ограничения на запросы на уровне приложения**: все запросы GraphRAG и предназначенные для пользователей применяют жесткие ограничения, поэтому широкие разделы никогда не сканируются полностью на пути горячего чтения. +**Cassandra эффективно обрабатывает частичные чтения**: сканирование кластерной колонки с ранней остановкой происходит быстро даже на больших разделах. +**Удаление коллекции** (единственная операция, которая может просматривать полные разделы) является приемлемым фоновым процессом. + +## Удаление коллекции + +Запускается по API-вызову, выполняется в фоновом режиме (с конечной согласованностью). + +1. Чтение `quads_by_collection` для целевой коллекции, чтобы получить все квадруплеты. +2. Извлечение уникальных сущностей из квадруплетов (значений s, p, o, d). +3. Для каждой уникальной сущности удалите раздел из `quads_by_entity`. +4. Удалите строки из `quads_by_collection`. + +Таблица `quads_by_collection` предоставляет индекс, необходимый для поиска всех разделов сущностей без полного сканирования таблицы. Удаление на уровне раздела эффективно, поскольку `(collection, entity)` является ключом раздела. + +## Путь миграции из многотабличной модели + +Модель, ориентированная на сущности, может сосуществовать с существующей многотабличной моделью во время миграции: + +1. Разверните таблицы `quads_by_entity` и `quads_by_collection` рядом с существующими таблицами. +2. Записывайте новые квадруплеты одновременно в старые и новые таблицы. +3. Заполните существующие данные в новые таблицы. +4. Мигрируйте пути запросов по одному шаблону за раз. +5. Отключите старые таблицы после миграции всех запросов. + +## Краткое описание + +| Аспект | Традиционная (6 таблиц) | Ориентированная на сущности (2 таблицы) | +|---|---|---| +| Таблицы | 7+ | 2 | +| Записи на квадруплет | 6+ | 5 (4 данных + 1 манифест) | +| Разрешение меток | Отдельные запросы | Бесплатно благодаря предварительной загрузке кэша | +| Шаблоны запросов | 16 по 6 таблицам | 16 на 1 таблицу | +| Сложность схемы | Высокая | Низкая | +| Операционные накладные расходы | 6 таблиц для настройки/восстановления | 1 таблица данных | +| Поддержка реификации | Дополнительная сложность | Естественная совместимость | +| Фильтрация по типу объекта | Недоступно | Нативно (через кластеризацию по типу объекта) | + diff --git a/docs/tech-specs/entity-centric-graph.sw.md b/docs/tech-specs/entity-centric-graph.sw.md new file mode 100644 index 00000000..fbbf6f7b --- /dev/null +++ b/docs/tech-specs/entity-centric-graph.sw.md @@ -0,0 +1,261 @@ +# Uhifadhi wa Mfumo wa Maarifa unaozingatia Vitu kwenye Cassandra + +## Muhtasari + +Hati hii inaelezea mfumo wa uhifadhi wa mifumo ya maarifa ya mtindo wa RDF kwenye Apache Cassandra. Mfumo hutumia mbinu inayozingatia **vitu**, ambapo kila kitu kinajua kila nne (quad) ambacho kinashiriki na jukumu ambalo linacheza. Hii inabadilisha mbinu ya awali ya meza nyingi zinazobadilisha mpangilio wa SPO kuwa meza mbili tu. + +## Asili na Lengo + +### Mbinu ya Jadi + +Hifadhi ya kawaida ya nne (quad) ya RDF kwenye Cassandra inahitaji meza nyingi zisizofaa ili kufidia mitindo ya maswali — kwa kawaida meza 6 au zaidi zinazowakilisha mabadiliko tofauti ya Mada (Subject), Kielelezo (Predicate), Kitu (Object), na Kundi (Dataset) (SPOD). Kila nne (quad) imeandikwa kwenye kila meza, na kusababisha ongezeko kubwa la uandishi, gharama za uendeshaji, na utata wa muundo. + +Zaidi ya hayo, utatuzi wa lebo (kupata majina yanayoweza kusomwa kwa urahisi kwa vitu) inahitaji maswali ya ziada, ambayo ni ya gharama kubwa hasa katika matumizi ya AI na GraphRAG ambapo lebo ni muhimu kwa muktadha wa LLM. + +### Mwangaza wa Mbinu inayozingatia Vitu + +Kila kikundi cha `(D, S, P, O)` kinahusisha hadi vitu 4. Kwa kuandika safu kwa kila shiriki la kitu katika kikundi, tunahakikisha kwamba **maswali yoyote yenye angalau kipengele kimoja kinachojulikana yatatumia ufunguo wa sehemu**. Hii inafunika mifumo yote 16 ya maswali na jedwali moja la data. + +Faida kuu: + +**Jedwali 2** badala ya 7+ +**Hali 4 kwa kila kikundi** badala ya 6+ +**Utatuzi wa lebo bila malipo** — lebo za kitu ziko karibu na uhusiano wake, na hivyo kuongeza kasi ya kumbukumbu ya programu. +**Mifumo yote 16 ya maswali** hutumika kwa usomaji wa sehemu moja. +**Utendaji rahisi** — jedwali moja la data ili kurekebisha, kupunguza, na kurekebisha. + +## Mpango + +### Jedwali 1: quads_by_entity + +Jedwali kuu la data. Kila kitu kina sehemu inayoyakilisha vikundi vyote ambavyo kitu hicho kinashiriki. Jina lake linaonyesha mfumo wa swali (utafutaji kwa kutumia kitu). + +```sql +CREATE TABLE quads_by_entity ( + collection text, -- Collection/tenant scope (always specified) + entity text, -- The entity this row is about + role text, -- 'S', 'P', 'O', 'G' — how this entity participates + p text, -- Predicate of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + s text, -- Subject of the quad + o text, -- Object of the quad + d text, -- Dataset/graph of the quad + dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string' + lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr' + PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang) +); +``` + +**Ufunguo wa partition:** `(collection, entity)` — unafichwa kwa mkusanyiko, na partition moja kwa kila entiti. + +**Mazingira ya utaratibu wa safu za kuunganisha (clustering):** + +1. **role** — maswali mengi huanza kwa "entiti hii ni mada/jambo" +2. **p** — chujio cha kawaida cha pili, "nipa uhusiano wote wa `knows`" +3. **otype** — inaruhusu kuchujwa kwa uhusiano wenye thamani ya URI dhidi ya uhusiano wenye thamani ya moja kwa moja +4. **s, o, d** — safu zilizobaki kwa uhakikisho +5. **dtype, lang** — hutofautisha maandishi yenye thamani sawa lakini metadata tofauti ya aina (k.m., `"thing"` vs `"thing"@en` vs `"thing"^^xsd:string`) + +### Jedwali 2: quads_by_collection + +Inasaidia maswali na uondoaji wa kiwango cha mkusanyiko. Inatoa orodha ya quads zote zinazohusiana na mkusanyiko. Imejina ili kuonyesha muundo wa swali (utafutaji kwa mkusanyiko). + +```sql +CREATE TABLE quads_by_collection ( + collection text, + d text, -- Dataset/graph of the quad + s text, -- Subject of the quad + p text, -- Predicate of the quad + o text, -- Object of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + dtype text, -- XSD datatype (when otype = 'L') + lang text, -- Language tag (when otype = 'L') + PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang) +); +``` + +Imefunganishwa kwanza kwa muundo wa data, na hivyo kuruhusu kufutwa kwa vitu au muundo wa data. Safu za `otype`, `dtype`, na `lang` zimejumuishwa katika ufunganishi ili kutofautisha vipengele ambavyo vina thamani sawa lakini data tofauti — katika RDF, `"thing"`, `"thing"@en`, na `"thing"^^xsd:string` ni thamani tofauti kwa maana. + +## Njia ya Kuandika + +Kwa kila kipengele kinachokuja `(D, S, P, O)` ndani ya mkusanyiko `C`, andika **safu 4** kwenye `quads_by_entity` na **safu 1** kwenye `quads_by_collection`. + +### Mfano + +Ikiwa kuna kipengele katika mkusanyiko `tenant1`: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: https://example.org/knows +Object: https://example.org/Bob +``` + +Andika mistari 4 hadi `quads_by_entity`: + +| mkusanyiko | kitu | jukumu | p | aina ya kitu | s | o | d | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | + +Andika mstari 1 hadi `quads_by_collection`: + +| mkusanyiko | d | s | p | o | aina ya kitu | aina ya data | lugha | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | | + +### Mfano Halisi + +Kwa jozi ya lebo: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: http://www.w3.org/2000/01/rdf-schema#label +Object: "Alice Smith" (lang: en) +``` + +Msimbo `otype` ni `'L'`, `dtype` ni `'xsd:string'`, na `lang` ni `'en'`. Thamani halisi `"Alice Smith"` huhifadhiwa katika `o`. Safu 3 tu zinahitajika katika `quads_by_entity` — hakuna safu inayorekodiwa kwa thamani kama kitu, kwa sababu vitu haviwezi kuchunguzwa kando. + +## Mifumo ya Uchunguzi + +### Mifumo 16 Yote ya DSPO + +Katika meza iliyo hapa chini, "Kielelezo kamili" ina maana kwamba swali hutumia kielelezo cha kuendelea cha safu za kuunganisha. "Ufuatiliaji wa sehemu + chujio" ina maana kwamba Cassandra husoma sehemu ya moja ya sehemu na kuchuja katika kumbukumbu — bado ni ufanisi, lakini sio mechi ya kielelezo safi. + +| # | Inajulikana | Tafuta kitu | Kielelezo cha kuunganisha | Ufanisi | +|---|---|---|---|---| +| 1 | D,S,P,O | kitu=S, jukumu='S', p=P | Mechi kamili | Kielelezo kamili | +| 2 | D,S,P,? | kitu=S, jukumu='S', p=P | Chujio kwenye D | Ufuatiliaji wa sehemu + chujio | +| 3 | D,S,?,O | kitu=S, jukumu='S' | Chujio kwenye D, O | Ufuatiliaji wa sehemu + chujio | +| 4 | D,?,P,O | kitu=O, jukumu='O', p=P | Chujio kwenye D | Ufuatiliaji wa sehemu + chujio | +| 5 | ?,S,P,O | kitu=S, jukumu='S', p=P | Chujio kwenye O | Ufuatiliaji wa sehemu + chujio | +| 6 | D,S,?,? | kitu=S, jukumu='S' | Chujio kwenye D | Ufuatiliaji wa sehemu + chujio | +| 7 | D,?,P,? | kitu=P, jukumu='P' | Chujio kwenye D | Ufuatiliaji wa sehemu + chujio | +| 8 | D,?,?,O | kitu=O, jukumu='O' | Chujio kwenye D | Ufuatiliaji wa sehemu + chujio | +| 9 | ?,S,P,? | kitu=S, jukumu='S', p=P | — | **Kielelezo kamili** | +| 10 | ?,S,?,O | kitu=S, jukumu='S' | Chujio kwenye O | Ufuatiliaji wa sehemu + chujio | +| 11 | ?,?,P,O | kitu=O, jukumu='O', p=P | — | **Kielelezo kamili** | +| 12 | D,?,?,? | kitu=D, jukumu='G' | — | **Kielelezo kamili** | +| 13 | ?,S,?,? | kitu=S, jukumu='S' | — | **Kielelezo kamili** | +| 14 | ?,?,P,? | kitu=P, jukumu='P' | — | **Kielelezo kamili** | +| 15 | ?,?,?,O | kitu=O, jukumu='O' | — | **Kielelezo kamili** | +| 16 | ?,?,?,? | — | Ufuatiliaji kamili | Uchunguzi tu | + +**Matokeo muhimu**: 7 kati ya mifumo 15 isiyo ya kawaida ni mechi kamili za kielelezo cha kuunganisha. Mifumo 8 iliyobaki ni usomaji wa sehemu moja na chujio ndani ya sehemu. Kila swali lenye kipengele kinachojulikana hupiga ufunguo wa sehemu. + +Mfumo 16 (?,?,?,?) haujulikani katika mazoezi kwa sababu mkusanyiko daima umeelezwa, na hivyo kuifanya iwe mfumo wa 12. + +### Mifano ya kawaida ya swali + +**Kila kitu kuhusu kitu:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'; +``` + +**Uhusiano wote unaotoka kwa kitu:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S'; +``` + +**Tabia maalum ya kitu:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows'; +``` + +**KILabeli kwa kitu (lugha mahususi):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label' +AND otype = 'L'; +``` + +Kisha, chambua matokeo kwa kutumia `lang = 'en'` upande wa programu, ikiwa ni lazima. + +**Tu uhusiano ambao una thamani ya URI (viungo vya aina ya kitu-kwa-kitu):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U'; +``` + +**Utafutaji wa kurudi nyuma — ni nini kinachoelekeza kwenye kitu hiki:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob' +AND role = 'O'; +``` + +## Utatuzi wa Lebo na Ukaushaji wa Kumbukumbu (Cache Warming) + +Moja ya faida muhimu zaidi ya mfumo unaozingatia vitu (entity-centric) ni kwamba **utatuzi wa lebo unakuwa matokeo ya ziada**. + +Katika mfumo wa zamani unaojumuisha meza nyingi, kupata lebo inahitaji maswali tofauti: pata triplet, tambua URI za vitu katika matokeo, kisha pata `rdfs:label` kwa kila moja. Mfumo huu wa N+1 ni ghali. + +Katika mfumo unaozingatia vitu, kuhoji kitu hurejesha **quads zote** - ikiwa ni pamoja na lebo zake, aina, na sifa zingine. Wakati programu inahifadhi matokeo ya maswali, lebo zimeandaliwa kabla ya chochote kuomba. + +Sera mbili za matumizi zinaonyesha kwamba hii inafanya kazi vizuri katika mazoezi: + +**Maswali yanayoeleweka na binadamu**: kawaida matokeo madogo, lebo ni muhimu. Maswali ya vitu huandalia kumbukumbu (cache). +**Maswali ya AI/wingi**: matokeo makubwa na mipaka ngumu. Lebo ama hazihitajiki au zinahitajika tu kwa sehemu ndogo ya vitu ambavyo tayari viko kwenye kumbukumbu. + +Wasiwasi wa kisia wa kutatua lebo kwa matokeo makubwa (k.m. vitu 30,000) hupunguzwa na utambuzi wa vitendo kwamba hakuna mtumiaji wa binadamu au AI anayeweza kuchakata lebo nyingi. Mipaka ya programu ya maswali inahakikisha kwamba shinikizo la kumbukumbu linabaki linaloweza kudhibitiwa. + +## Sehemu Zinazopaswa Kusambazwa na Ufafanuzi + +Ufafanuzi (taarifa za aina ya RDF-star kuhusu taarifa) huunda vitu vya kitovu - k.m. hati ya chanzo ambayo inasaidia ukweli mwingi uliotolewa. Hii inaweza kuzalisha sehemu zinazopaswa kusambazwa. + +Mambo yanayoweza kupunguza: + +**Mipaka ya maswali ya programu**: maswali yote ya GraphRAG na yale yanayoeleweka na binadamu yana mipaka ngumu, kwa hivyo sehemu zinazopaswa kusambazwa hazisomwi kamwe kwa upeo wa njia ya usomaji. +**Cassandra inashughulikia usomaji wa sehemu kwa ufanisi**: uchanganuzi wa safu ya ufunguo wa uainishaji na kusimamishwa mapema ni wa haraka hata kwenye sehemu kubwa. +**Ufutaji wa mkusanyiko** (operesheni pekee ambayo inaweza kuvuka sehemu kamili) ni mchakato unaokubalika wa asili. + +## Ufufuo wa Mkusaniko + +Huendeshwa na wito wa API, inafanya kazi kwa asili (inatimiza kwa wakati). + +1. Soma `quads_by_collection` kwa mkusanyiko unaolengwa ili kupata quads zote. +2. Toa vitu vya kipekee kutoka kwa quads (mahesabu ya s, p, o, d). +3. Kwa kila kitu cha kipekee, futa sehemu kutoka kwa `quads_by_entity`. +4. Futa mistari kutoka kwa `quads_by_collection`. + +Jedwali la `quads_by_collection` hutoa fahirisi inayohitajika ili kupata sehemu zote za kitu bila uchanganuzi kamili wa jedwali. Ufufuo wa kiwango cha sehemu ni wa ufanisi kwa sababu `(collection, entity)` ndio ufunguo wa sehemu. + +## Njia ya Uhamishaji kutoka kwa Mfumo wa Meza Nyingi + +Mfumo unaozingatia vitu unaweza kuwepo na mfumo wa zamani unaojumuisha meza nyingi wakati wa uhamishaji: + +1. Weka meza za `quads_by_entity` na `quads_by_collection` pamoja na meza zilizopo. +2. Andika quads mpya kwa meza zote mbili za zamani na mpya. +3. Jaza data iliyopo kwenye meza mpya. +4. Hamisha njia za maswali moja kwa moja. +5. Ondoa meza za zamani baada ya maswali yote kuhamishwa. + +## Muhtasari + +| Nguvu | Zamani (meza 6) | Kitu (meza 2) | +|---|---|---| +| Meza | 7+ | 2 | +| Andishi kwa kila quad | 6+ | 5 (4 data + 1 manifest) | +| Utafiti wa lebo | Safari tofauti | Bila shida kupitia ukaushaji wa kumbukumbu | +| Mfumo wa maswali | 16 katika meza 6 | 16 katika meza 1 | +| Ufumbuzi wa mpango | Wa juu | Wa chini | +| Uendeshaji | Meza 6 za kurekebisha/kufufua | Jedwali 1 la data | +| Usaidizi wa ufafanuzi | Ufumbuzi wa ziada | Inafaa asili | +| Uchunguzi wa aina ya kitu | Haipatikani | Asili (kupitia uainishaji wa otype) | + diff --git a/docs/tech-specs/entity-centric-graph.tr.md b/docs/tech-specs/entity-centric-graph.tr.md new file mode 100644 index 00000000..1507a4fe --- /dev/null +++ b/docs/tech-specs/entity-centric-graph.tr.md @@ -0,0 +1,261 @@ +# Cassandra'da Varlık Odaklı Bilgi Grafiği Depolama + +## Genel Bakış + +Bu belge, Apache Cassandra üzerindeki RDF tarzı bilgi grafiklerinin depolanması için bir model tanımlamaktadır. Model, her varlığın katıldığı her dörtlü hakkında bilgi sahibi olduğu ve oynadığı rolün bilindiği, **varlık odaklı** bir yaklaşım kullanır. Bu, geleneksel çok tablolu SPO permütasyon yaklaşımının yerini sadece iki tabloyla alır. + +## Arka Plan ve Motivasyon + +### Geleneksel Yaklaşım + +Cassandra'daki standart bir RDF dörtlü deposu, sorgu kalıplarını kapsamak için birden fazla denormalize edilmiş tablo gerektirir; tipik olarak, Konu, Özne, Nesne ve Veri Kümesi (SPOD) permütasyonlarının farklı temsillerini içeren 6 veya daha fazla tablo. Her dörtlü, her tabloya yazılır, bu da önemli bir yazma çoğaltmasına, operasyonel yüke ve şema karmaşıklığına yol açar. + +Ek olarak, etiket çözümü (varlıklar için okunabilir adların alınması), ayrı gidiş-dönüş sorguları gerektirir ve bu da, etiketlerin LLM bağlamı için önemli olduğu yapay zeka ve GraphRAG kullanım durumlarında özellikle maliyetlidir. + +### Varlık Odaklı İçgörü + +Her bir dörtlü `(D, S, P, O)`, en fazla 4 varlığı içerir. Her bir varlığın dörtlüdeki katılımını bir satırla belirterek, **en az bir bilinen öğesi olan her sorgunun bir bölüm anahtarını hedefleyeceğinden emin oluruz**. Bu, tek bir veri tablosuyla tüm 16 sorgu desenini kapsar. + +Temel avantajlar: + +**7'den fazla yerine 2 tablo** +**6'dan fazla yerine, her dörtlü için 4 yazma işlemi** +**Etiket çözümlemesi ücretsiz** — bir varlığın etiketleri, ilişkileriyle birlikte bulunur ve bu da uygulama önbelleğini doğal olarak önceden doldurur. +**Tüm 16 sorgu deseni**, tek bölüm okumalarıyla sağlanır. +**Daha basit işlemler** — ayarlanması, sıkıştırılması ve onarılması gereken tek bir veri tablosu. + +## Şema + +### Tablo 1: quads_by_entity + +Birincil veri tablosu. Her varlığın, katıldığı tüm dörtlüleri içeren bir bölümü vardır. Sorgu desenini yansıtacak şekilde adlandırılmıştır (varlık bazında arama). + +```sql +CREATE TABLE quads_by_entity ( + collection text, -- Collection/tenant scope (always specified) + entity text, -- The entity this row is about + role text, -- 'S', 'P', 'O', 'G' — how this entity participates + p text, -- Predicate of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + s text, -- Subject of the quad + o text, -- Object of the quad + d text, -- Dataset/graph of the quad + dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string' + lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr' + PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang) +); +``` + +**Bölüm anahtarı**: `(collection, entity)` — koleksiyona özel, her varlık için bir bölüm. + +**Kümeleme sütun sıralama gerekçesi**: + +1. **role** — çoğu sorgu, "bu varlık bir konu mu/nesne mi" şeklinde başlar. +2. **p** — en yaygın filtrelerden ikincisi, "bana tüm `knows` ilişkilerini ver". +3. **otype** — URI değeri olan ilişkileri, literal değeri olan ilişkilerden ayırmayı sağlar. +4. **s, o, d** — benzersizlik için kalan sütunlar. +5. **dtype, lang** — aynı değere sahip ancak farklı tür meta verilerine sahip literal değerleri ayırt eder (örneğin, `"thing"` vs `"thing"@en` vs `"thing"^^xsd:string`). + +### Tablo 2: quads_by_collection + +Koleksiyon seviyesindeki sorguları ve silme işlemlerini destekler. Bir koleksiyona ait olan tüm dörtlülerin bir listesini sağlar. Sorgu desenini yansıtacak şekilde adlandırılmıştır (koleksiyona göre arama). + +```sql +CREATE TABLE quads_by_collection ( + collection text, + d text, -- Dataset/graph of the quad + s text, -- Subject of the quad + p text, -- Predicate of the quad + o text, -- Object of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + dtype text, -- XSD datatype (when otype = 'L') + lang text, -- Language tag (when otype = 'L') + PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang) +); +``` + +İlk olarak veri kümesi bazında gruplandırılır, bu da silme işleminin ya koleksiyon düzeyinde ya da veri kümesi düzeyinde yapılabilmesini sağlar. `otype`, `dtype` ve `lang` sütunları, aynı değere sahip ancak farklı tür meta verilerine sahip literal değerleri ayırt etmek için kümeleme anahtarına dahil edilmiştir; RDF'de, `"thing"`, `"thing"@en` ve `"thing"^^xsd:string` semantik olarak farklı değerlerdir. + +## Yazma Yolu + +Her bir koleksiyon içindeki `C` içinde gelen `(D, S, P, O)` dörtlüsü için, **4 satır** `quads_by_entity`'ye ve **1 satır** `quads_by_collection`'e yazın. + +### Örnek + +Koleksiyon içindeki `tenant1` dörtgeni verildiğinde: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: https://example.org/knows +Object: https://example.org/Bob +``` + +`quads_by_entity`'e 4 satır yazın: + +| collection | entity | role | p | otype | s | o | d | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | + +`quads_by_collection`'e 1 satır yazın: + +| collection | d | s | p | o | otype | dtype | lang | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | | + +### Literal Example + +Bir etiket üçlüsü için: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: http://www.w3.org/2000/01/rdf-schema#label +Object: "Alice Smith" (lang: en) +``` + +`otype` değeri `'L'`, `dtype` değeri `'xsd:string'` ve `lang` değeri `'en'`'tir. Literal değer olan `"Alice Smith"`, `o` içinde saklanır. `quads_by_entity`'de yalnızca 3 satır gereklidir; literal, bir varlık olarak bağımsız olarak sorgulanamayan bir şey olduğu için, literal için herhangi bir satır yazılmaz. + +## Sorgu Desenleri + +### Tüm 16 DSPO Deseni + +Aşağıdaki tabloda, "Mükemmel önek", sorgunun kümeleme sütunlarının ardışık bir önekini kullandığı anlamına gelir. "Bölüm taraması + filtre", Cassandra'nın bir bölümün bir dilimini okuduğu ve bellekte filtreleme yaptığı anlamına gelir; bu, verimli olsa da, saf bir önek eşleşmesi değildir. + +| # | Bilinen | Varlık | Kümeleme öneki | Verimlilik | +|---|---|---|---|---| +| 1 | D,S,P,O | entity=S, role='S', p=P | Tam eşleşme | Mükemmel önek | +| 2 | D,S,P,? | entity=S, role='S', p=P | D üzerinde filtreleme | Bölüm taraması + filtre | +| 3 | D,S,?,O | entity=S, role='S' | D, O üzerinde filtreleme | Bölüm taraması + filtre | +| 4 | D,?,P,O | entity=O, role='O', p=P | D üzerinde filtreleme | Bölüm taraması + filtre | +| 5 | ?,S,P,O | entity=S, role='S', p=P | O üzerinde filtreleme | Bölüm taraması + filtre | +| 6 | D,S,?,? | entity=S, role='S' | D üzerinde filtreleme | Bölüm taraması + filtre | +| 7 | D,?,P,? | entity=P, role='P' | D üzerinde filtreleme | Bölüm taraması + filtre | +| 8 | D,?,?,O | entity=O, role='O' | D üzerinde filtreleme | Bölüm taraması + filtre | +| 9 | ?,S,P,? | entity=S, role='S', p=P | — | **Mükemmel önek** | +| 10 | ?,S,?,O | entity=S, role='S' | O üzerinde filtreleme | Bölüm taraması + filtre | +| 11 | ?,?,P,O | entity=O, role='O', p=P | — | **Mükemmel önek** | +| 12 | D,?,?,? | entity=D, role='G' | — | **Mükemmel önek** | +| 13 | ?,S,?,? | entity=S, role='S' | — | **Mükemmel önek** | +| 14 | ?,?,P,? | entity=P, role='P' | — | **Mükemmel önek** | +| 15 | ?,?,?,O | entity=O, role='O' | — | **Mükemmel önek** | +| 16 | ?,?,?,? | — | Tam tarama | Yalnızca keşif | + +**Önemli sonuç**: 15 önemsiz desenden 7'si mükemmel kümeleme önek eşleşmesidir. Kalan 8 tanesi, bölüm içi filtrelemeyle birlikte tek bölümlü okumalardır. En az bir bilinen öğeye sahip her sorgu, bir bölüm anahtarını etkiler. + +Desen 16 (?,?,?,?) pratikte oluşmaz, çünkü koleksiyon her zaman belirtilir ve bu da onu desen 12'ye indirger. + +### Yaygın Sorgu Örnekleri + +**Bir varlık hakkında her şey:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'; +``` + +**Bir varlık için tüm dış ilişkiler:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S'; +``` + +**Bir varlık için özel koşul:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows'; +``` + +**Bir varlık için etiket (belirli bir dil):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label' +AND otype = 'L'; +``` + +Gerekirse, `lang = 'en'` uygulamasının tarafında filtreleme yapın. + +**Sadece URI değerine sahip ilişkiler (varlıklar arası bağlantılar):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U'; +``` + +**Ters sorgulama — bu varlığa neyin işaret ettiği:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob' +AND role = 'O'; +``` + +## Etiket Çözümleme ve Önbellek Isıtma + +Varlık odaklı modelin en önemli avantajlarından biri, **etiket çözümlemenin ücretsiz bir yan etki olmasıdır**. + +Geleneksel çok tablolu modelde, etiketleri almak ayrı sorgu istekleri gerektirir: üçlüleri alın, sonuçlardaki varlık URI'larını belirleyin ve ardından her biri için `rdfs:label` alın. Bu N+1 deseni maliyetlidir. + +Varlık odaklı modelde, bir varlığı sorgulamak, etiketleri, türleri ve diğer özellikleri de içeren **tüm** dörtlülerini döndürür. Uygulama sorgu sonuçlarını önbelleğe aldığında, etiketler herhangi bir şey onlardan istekte bulunmadan önce önceden ısıtılır. + +İki kullanım rejimi, bunun pratikte iyi çalıştığını doğrulamaktadır: + +**Kullanıcı arayüzüne yönelik sorgular**: doğal olarak küçük sonuç kümeleri, etiketler önemlidir. Varlık okumaları önbelleği önceden ısıtır. +**AI/toplu sorgular**: büyük sonuç kümeleri ve sıkı sınırlar. Etiketler ya gereksizdir ya da önceden önbelleğe alınmış olan varlıkların yalnızca seçilmiş bir alt kümesi için gereklidir. + +Çok büyük sonuç kümeleri (örneğin, 30.000 varlık) için etiketleri çözme konusundaki teorik endişe, hiçbir insan veya yapay zeka tüketicisinin o kadar çok etiketi faydalı bir şekilde işlemediği pratik gözlemiyle giderilir. Uygulama düzeyindeki sorgu sınırları, önbellek üzerindeki baskının yönetilebilir kalmasını sağlar. + +## Geniş Bölümler ve Somutlaştırma + +Somutlaştırma (RDF-star tarzı, ifadeler hakkında ifadeler), kaynak belge gibi merkez varlıkları oluşturur; bu belge, çıkarılan binlerce olguyu destekler. Bu, geniş bölümlere yol açabilir. + +Hafifletici faktörler: + +**Uygulama düzeyindeki sorgu sınırları**: tüm GraphRAG ve kullanıcı arayüzüne yönelik sorgular, geniş bölümlerin sıcak okuma yolunda asla tamamen taranmamasını sağlayan sıkı sınırlar uygular. +**Cassandra, kısmi okumaları verimli bir şekilde işler**: erken durdurma ile bir küme sütunu taraması, büyük bölümlerde bile hızlıdır. +**Koleksiyon silme** (sadece tüm bölümleri geçebilecek bir işlem), kabul edilebilir bir arka plan işlemidir. + +## Koleksiyon Silme + +API çağrısı tarafından tetiklenir, arka planda çalışır (eventually consistent). + +1. Hedef koleksiyon için `quads_by_collection`'ı okuyun ve tüm dörtlüleri alın. +2. Dörtlülerden benzersiz varlıkları çıkarın (s, p, o, d değerleri). +3. Her benzersiz varlık için, `quads_by_entity`'dan ilgili bölümü silin. +4. `quads_by_collection`'dan satırları silin. + +`quads_by_collection` tablosu, tüm varlık bölümlerini tam tablo taraması olmadan bulmak için gereken dizini sağlar. Bölüm düzeyindeki silmeler verimlidir çünkü `(collection, entity)` bölüm anahtarıdır. + +## Çok Tablolu Modelden Geçiş Yolu + +Varlık odaklı model, geçiş sırasında mevcut çok tablolu modelle birlikte var olabilir: + +1. `quads_by_entity` ve `quads_by_collection` tablolarını mevcut tablolara ek olarak dağıtın. +2. Yeni dörtlüleri hem eski hem de yeni tablolara çift yazın. +3. Mevcut verileri yeni tablolara geri yükleyin. +4. Okuma yollarını bir sorgu deseni bir seferinde geçirin. +5. Tüm okumalar geçirildikten sonra eski tabloları devre dışı bırakın. + +## Özet + +| Yön | Geleneksel (6 tablo) | Varlık odaklı (2 tablo) | +|---|---|---| +| Tablolar | 7+ | 2 | +| Dörtlü başına yazma | 6+ | 5 (4 veri + 1 manifest) | +| Etiket çözümleme | Ayrı sorgu istekleri | Önbellek ısıtma yoluyla ücretsiz | +| Sorgu desenleri | 6 tabloda 16 | 1 tabloda 16 | +| Şema karmaşıklığı | Yüksek | Düşük | +| İşletimsel yük | Ayarlanması/onarılması gereken 6 tablo | 1 veri tablosu | +| Somutlaştırma desteği | Ek karmaşıklık | Doğal uyum | +| Nesne türü filtreleme | Kullanılamaz | Yerel (o tür kümeleme yoluyla) | +ÇIKTI SÖZLEŞMESİ (tam olarak aşağıdaki formatı takip etmelidir): diff --git a/docs/tech-specs/entity-centric-graph.zh-cn.md b/docs/tech-specs/entity-centric-graph.zh-cn.md new file mode 100644 index 00000000..46ce4971 --- /dev/null +++ b/docs/tech-specs/entity-centric-graph.zh-cn.md @@ -0,0 +1,261 @@ +# 基于实体的知识图谱在 Cassandra 上的存储 + +## 概述 + +本文档描述了一种在 Apache Cassandra 上存储 RDF 风格知识图谱的存储模型。该模型采用一种**以实体为中心**的方法,其中每个实体都知道它参与的所有四元组以及它所扮演的角色。这用两个表替换了传统的多表 SPO 组合方法。 + +## 背景和动机 + +### 传统方法 + +在 Cassandra 上,标准的 RDF 四元组存储需要多个反规范化的表来覆盖查询模式,通常需要 6 个或更多的表,这些表代表主语、谓词、宾语和数据集 (SPOD) 的不同组合。每个四元组都会写入到每个表中,从而导致显著的写入放大、运维开销和模式复杂性。 + +此外,标签解析(用于实体的人类可读名称)需要单独的往返查询,这在 AI 和 GraphRAG 用例中尤其昂贵,因为标签对于 LLM 上下文至关重要。 + +### 以实体为中心的洞察 + +每个四元组 `(D, S, P, O)` 涉及最多 4 个实体。通过为每个实体参与四元组的记录创建一个行,我们保证**任何至少包含一个已知元素的查询都会命中分区键**。这使用单个数据表覆盖所有 16 种查询模式。 + +主要优点: + +**2 个表**,而不是 7 个以上 +**每个四元组 4 次写入**,而不是 6 次以上 +**免费的标签解析**——实体的标签与其关系共存,从而自然地预热应用程序缓存 +**所有 16 种查询模式**都由单分区读取提供 +**更简单的操作**——只有一个数据表需要调整、压缩和修复 + +## 模式 + +### 表 1:quads_by_entity + +主要数据表。每个实体都有一个分区,其中包含它参与的所有四元组。该名称反映了查询模式(按实体查找)。 + +```sql +CREATE TABLE quads_by_entity ( + collection text, -- Collection/tenant scope (always specified) + entity text, -- The entity this row is about + role text, -- 'S', 'P', 'O', 'G' — how this entity participates + p text, -- Predicate of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + s text, -- Subject of the quad + o text, -- Object of the quad + d text, -- Dataset/graph of the quad + dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string' + lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr' + PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang) +); +``` + +**分区键 (Partition key)**: `(collection, entity)` — 作用域限定在集合中,每个实体对应一个分区。 + +**聚类列顺序的理由 (Clustering column order rationale)**: + +1. **role** — 大部分查询都以“这个实体是哪个主语/客体”开始。 +2. **p** — 下一个最常见的过滤条件,例如“给我所有 `knows` 关系”。 +3. **otype** — 允许根据 URI 值与字面值关系进行过滤。 +4. **s, o, d** — 剩余的列用于保证唯一性。 +5. **dtype, lang** — 区分具有相同值但不同类型元数据的字面值(例如,`"thing"` 与 `"thing"@en` 与 `"thing"^^xsd:string`)。 + +### 表 2: quads_by_collection + +支持集合级别的查询和删除。提供属于某个集合的所有四元组的清单。命名方式反映了查询模式(按集合查找)。 + +```sql +CREATE TABLE quads_by_collection ( + collection text, + d text, -- Dataset/graph of the quad + s text, -- Subject of the quad + p text, -- Predicate of the quad + o text, -- Object of the quad + otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification) + dtype text, -- XSD datatype (when otype = 'L') + lang text, -- Language tag (when otype = 'L') + PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang) +); +``` + +首先按照数据集进行聚类,从而可以在集合或数据集级别进行删除。 `otype`、`dtype` 和 `lang` 列包含在聚类键中,用于区分具有相同值但不同元数据类型的字面量——在 RDF 中,`"thing"`、`"thing"@en` 和 `"thing"^^xsd:string` 是语义上不同的值。 + +## 写入路径 + +对于每个在集合 `C` 中的四元组 `(D, S, P, O)`,需要向 `quads_by_entity` 写入 **4 行**,并向 `quads_by_collection` 写入 **1 行**。 + +### 示例 + +假设在集合 `tenant1` 中的四元组是: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: https://example.org/knows +Object: https://example.org/Bob +``` + +将 4 行写入到 `quads_by_entity`: + +| collection | entity | role | p | otype | s | o | d | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | +| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 | + +将 1 行写入到 `quads_by_collection`: + +| collection | d | s | p | o | otype | dtype | lang | +|---|---|---|---|---|---|---|---| +| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | | + +### 示例 + +对于一个标签三元组: + +``` +Dataset: https://example.org/graph1 +Subject: https://example.org/Alice +Predicate: http://www.w3.org/2000/01/rdf-schema#label +Object: "Alice Smith" (lang: en) +``` + +`otype` 是 `'L'`,`dtype` 是 `'xsd:string'`,`lang` 是 `'en'`。 原始值 `"Alice Smith"` 存储在 `o` 中。 `quads_by_entity` 中只需要 3 行,因为没有为原始值作为实体的行,因为原始值不是可以独立查询的实体。 + +## 查询模式 + +### 所有 16 种 DSPO 模式 + +在下表中,“完美前缀”表示查询使用聚类列的连续前缀。“分区扫描 + 过滤”表示 Cassandra 读取一个分区的一部分并在内存中进行过滤,这仍然有效,但不是纯粹的前缀匹配。 + +| # | 已知 | 查找实体 | 聚类前缀 | 效率 | +|---|---|---|---|---| +| 1 | D,S,P,O | entity=S, role='S', p=P | 完全匹配 | 完美前缀 | +| 2 | D,S,P,? | entity=S, role='S', p=P | 在 D 上过滤 | 分区扫描 + 过滤 | +| 3 | D,S,?,O | entity=S, role='S' | 在 D, O 上过滤 | 分区扫描 + 过滤 | +| 4 | D,?,P,O | entity=O, role='O', p=P | 在 D 上过滤 | 分区扫描 + 过滤 | +| 5 | ?,S,P,O | entity=S, role='S', p=P | 在 O 上过滤 | 分区扫描 + 过滤 | +| 6 | D,S,?,? | entity=S, role='S' | 在 D 上过滤 | 分区扫描 + 过滤 | +| 7 | D,?,P,? | entity=P, role='P' | 在 D 上过滤 | 分区扫描 + 过滤 | +| 8 | D,?,?,O | entity=O, role='O' | 在 D 上过滤 | 分区扫描 + 过滤 | +| 9 | ?,S,P,? | entity=S, role='S', p=P | — | **完美前缀** | +| 10 | ?,S,?,O | entity=S, role='S' | 在 O 上过滤 | 分区扫描 + 过滤 | +| 11 | ?,?,P,O | entity=O, role='O', p=P | — | **完美前缀** | +| 12 | D,?,?,? | entity=D, role='G' | — | **完美前缀** | +| 13 | ?,S,?,? | entity=S, role='S' | — | **完美前缀** | +| 14 | ?,?,P,? | entity=P, role='P' | — | **完美前缀** | +| 15 | ?,?,?,O | entity=O, role='O' | — | **完美前缀** | +| 16 | ?,?,?,? | — | 全扫描 | 仅探索 | + +**关键结果:** 15 种非平凡模式中有 7 种是完美的聚类前缀匹配。 剩下的 8 种是单分区读取,并在分区内进行过滤。 包含至少一个已知元素的每个查询都会命中分区键。 + +模式 16 (?,?,?,?) 在实践中不会出现,因为集合始终是指定的,这将其简化为模式 12。 + +### 常见查询示例 + +**关于一个实体的所有信息:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'; +``` + +**实体的所有出方向关系:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S'; +``` + +**特定实体谓词:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows'; +``` + +**实体标签(特定语言):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label' +AND otype = 'L'; +``` + +然后,如果需要,可以在应用程序端通过 `lang = 'en'` 进行过滤。 + +**仅限 URI 值的关系(实体到实体的链接):** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice' +AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U'; +``` + +**反向查找 — 指向此实体的对象:** + +```sql +SELECT * FROM quads_by_entity +WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob' +AND role = 'O'; +``` + +## 标签解析和缓存预热 + +实体中心模型最显著的优势之一是,**标签解析成为一个免费的副作用**。 + +在传统的基于多表的模型中,获取标签需要单独的轮询查询:检索三元组,识别结果中的实体 URI,然后为每个 URI 获取 `rdfs:label`。 这种 N+1 模式非常昂贵。 + +在实体中心模型中,查询一个实体会返回其**所有**四元组,包括其标签、类型和其他属性。 当应用程序缓存查询结果时,标签会在任何客户端请求之前被预热。 + +两种使用模式证实了这在实践中效果良好: + +**面向用户的查询**:结果集通常很小,标签至关重要。 实体读取会预热缓存。 +**AI/批量查询**:结果集很大,但有严格的限制。 标签要么是不必要的,要么只需要用于已缓存的实体子集。 + +解决大型结果集(例如 30,000 个实体)的标签的理论问题,可以通过实际观察来缓解,即没有人类或 AI 消费者能够有效地处理如此多的标签。 应用程序级别的查询限制可确保缓存压力保持在可管理范围内。 + +## 宽分区和重构 + +重构(RDF-star 风格的关于语句的语句)会创建中心实体,例如,一个源文档支持数千个提取的事实。 这可能会导致宽分区。 + +缓解因素: + +**应用程序级别的查询限制**:所有 GraphRAG 和面向用户的查询都强制执行严格的限制,因此宽分区永远不会在热读取路径上被完全扫描。 +**Cassandra 可以高效地执行部分读取**:即使在大型分区上,具有早期停止的聚类列扫描也是快速的。 +**集合删除**(唯一可能遍历整个分区的操作)是一个可接受的后台过程。 + +## 集合删除 + +由 API 调用触发,在后台运行(最终一致)。 + +1. 读取 `quads_by_collection` 以获取目标集合的所有四元组 +2. 从四元组中提取唯一的实体(s、p、o、d 值) +3. 对于每个唯一的实体,从 `quads_by_entity` 中删除该分区 +4. 从 `quads_by_collection` 中删除行 + +`quads_by_collection` 表提供了用于定位所有实体分区而无需进行全表扫描所需的索引。 由于 `(collection, entity)` 是分区键,因此分区级别的删除是高效的。 + +## 从多表模型迁移的路径 + +在迁移过程中,实体中心模型可以与现有的多表模型共存: + +1. 将 `quads_by_entity` 和 `quads_by_collection` 表与现有表一起部署 +2. 同时将新的四元组写入旧表和新表 +3. 将现有数据回填到新表中 +4. 每次迁移一种查询模式 +5. 在迁移所有读取路径后,停用旧表 + +## 总结 + +| 方面 | 传统 (6 个表) | 实体中心 (2 个表) | +|---|---|---| +| 表 | 7+ | 2 | +| 每个四元组的写入次数 | 6+ | 5 (4 个数据 + 1 个清单) | +| 标签解析 | 单独的轮询 | 通过缓存预热免费 | +| 查询模式 | 6 个表中的 16 种 | 1 个表中的 16 种 | +| 模式复杂性 | 高 | 低 | +| 运维开销 | 6 个表需要调整/修复 | 1 个数据表 | +| 重构支持 | 额外的复杂性 | 完美契合 | +| 对象类型过滤 | 不可用 | 原生 (通过 otype 聚类) | +输出合同(必须严格遵守以下格式): diff --git a/docs/tech-specs/explainability-cli.he.md b/docs/tech-specs/explainability-cli.he.md new file mode 100644 index 00000000..60804f1b --- /dev/null +++ b/docs/tech-specs/explainability-cli.he.md @@ -0,0 +1,220 @@ +# מפרט טכני של כלי שורת הפקודה (CLI) להסברתיות + +## סטטוס + +טיוטה + +## סקירה כללית + +מפרט זה מתאר כלי שורת פקודה (CLI) לניפוי באגים ובדיקת נתוני הסברתיות ב-TrustGraph. כלים אלה מאפשרים למשתמשים לעקוב אחר אופן קבלת התשובות ולבצע ניפוי באגים בשרשרת המקור, החל מצמתים ועד למסמכים מקוריים. + +שלושה כלים של שורת פקודה: + +1. **`tg-show-document-hierarchy`** - הצגת היררכיה של מסמך → עמוד → מקטע → צומת +2. **`tg-list-explain-traces`** - הצגת רשימה של כל הסשנים של GraphRAG עם שאלות +3. **`tg-show-explain-trace`** - הצגת מעקב הסברתיות מלא עבור סשן + +## מטרות + +**ניפוי באגים**: לאפשר למפתחים לבדוק את תוצאות עיבוד המסמכים +**ביקורת**: לעקוב אחר כל עובדה שחולצה בחזרה למסמך המקור שלה +**שקיפות**: להציג בדיוק כיצד GraphRAG הגיע לתשובה +**שימושיות**: ממשק שורת פקודה פשוט עם הגדרות ברירת מחדל הגיוניות + +## רקע + +ל-TrustGraph יש שתי מערכות מעקב מקור: + +1. **מעקב מקור בזמן חילוץ** (ראה `extraction-time-provenance.md`): מתעד את היחסים בין מסמך → עמוד → מקטע → צומת במהלך הטעינה. מאוחסן בגרף בשם `urn:graph:source` באמצעות `prov:wasDerivedFrom`. + +2. **הסברתיות בזמן שאילתה** (ראה `query-time-explainability.md`): מתעד את שרשרת השאלות → חקירה → מיקוד → סינתזה במהלך שאילתות GraphRAG. מאוחסן בגרף בשם `urn:graph:retrieval`. + +מגבלות נוכחיות: +אין דרך קלה להציג את היררכיית המסמכים לאחר העיבוד +יש לבצע שאילתות ידניות על משולשים כדי לראות נתוני הסברתיות +אין תצוגה מאוחדת של סשן GraphRAG + +## עיצוב טכני + +### כלי 1: tg-show-document-hierarchy + +**מטרה**: בהינתן מזהה מסמך, לעבור ולציין את כל הישויות הנגזרות. + +**שימוש**: +```bash +tg-show-document-hierarchy "urn:trustgraph:doc:abc123" +tg-show-document-hierarchy --show-content --max-content 500 "urn:trustgraph:doc:abc123" +``` + +**ארגומנטים**: +| Arg | תיאור | +|-----|-------------| +| `document_id` | כתובת URI של המסמך (מיקום) | +| `-u/--api-url` | כתובת URL של ה-Gateway (ברירת מחדל: `$TRUSTGRAPH_URL`) | +| `-t/--token` | טוקן אימות (ברירת מחדל: `$TRUSTGRAPH_TOKEN`) | +| `-U/--user` | מזהה משתמש (ברירת מחדל: `trustgraph`) | +| `-C/--collection` | אוסף (ברירת מחדל: `default`) | +| `--show-content` | לכלול תוכן של קבצים/מסמכים | +| `--max-content` | מספר תווים מקסימלי לכל קובץ (ברירת מחדל: 200) | +| `--format` | פלט: `tree` (ברירת מחדל), `json` | + +**יישום**: +1. שאילת משולשות: `?child prov:wasDerivedFrom ` ב-`urn:graph:source` +2. שאילת באופן רקורסיבי את הילדים של כל תוצאה +3. בניית מבנה עץ: מסמך → עמודים → חלקים +4. אם `--show-content`, שליפה של תוכן מ-API של הספרן +5. הצגה כמבנה עץ עם הזחות או JSON + +**דוגמה לפלט**: +``` +Document: urn:trustgraph:doc:abc123 + Title: "Sample PDF" + Type: application/pdf + + └── Page 1: urn:trustgraph:doc:abc123/p1 + ├── Chunk 0: urn:trustgraph:doc:abc123/p1/c0 + │ Content: "The quick brown fox..." [truncated] + └── Chunk 1: urn:trustgraph:doc:abc123/p1/c1 + Content: "Machine learning is..." [truncated] +``` + +### כלי 2: tg-list-explain-traces + +**מטרה**: הצגת כל הסשנים (שאלות) של GraphRAG באוסף. + +**שימוש**: +```bash +tg-list-explain-traces +tg-list-explain-traces --limit 20 --format json +``` + +**ארגומנטים**: +| Arg | תיאור | +|-----|-------------| +| `-u/--api-url` | כתובת URL של ה-Gateway | +| `-t/--token` | טוקן אימות | +| `-U/--user` | מזהה משתמש | +| `-C/--collection` | אוסף | +| `--limit` | מספר תוצאות מקסימלי (ברירת מחדל: 50) | +| `--format` | פלט: `table` (ברירת מחדל), `json` | + +**יישום**: +1. שאילתה: `?session tg:query ?text` ב-`urn:graph:retrieval` +2. שאילתת חותמות זמן: `?session prov:startedAtTime ?time` +3. הצגה כטבלה + +**דוגמה לפלט**: +``` +Session ID | Question | Time +----------------------------------------------|--------------------------------|--------------------- +urn:trustgraph:question:abc123 | What was the War on Terror? | 2024-01-15 10:30:00 +urn:trustgraph:question:def456 | Who founded OpenAI? | 2024-01-15 09:15:00 +``` + +### כלי 3: tg-show-explain-trace + +**מטרה**: הצגת שרשרת ההסברים המלאה עבור סשן GraphRAG. + +**שימוש**: +```bash +tg-show-explain-trace "urn:trustgraph:question:abc123" +tg-show-explain-trace --max-answer 1000 --show-provenance "urn:trustgraph:question:abc123" +``` + +**ארגומנטים**: +| Arg | תיאור | +|-----|-------------| +| `question_id` | כתובת URI של שאלה (מיקום) | +| `-u/--api-url` | כתובת URL של שער | +| `-t/--token` | טוקן אימות | +| `-U/--user` | מזהה משתמש | +| `-C/--collection` | אוסף | +| `--max-answer` | מספר תווים מקסימלי לתשובה (ברירת מחדל: 500) | +| `--show-provenance` | לעקוב אחר קשרים למסמכים מקוריים | +| `--format` | פלט: `text` (ברירת מחדל), `json` | + +**יישום**: +1. קבל את טקסט השאלה מ-`tg:query` (predicate) +2. מצא חקירה: `?exp prov:wasGeneratedBy ` +3. מצא מיקוד: `?focus prov:wasDerivedFrom ` +4. קבל קשרים שנבחרו: ` tg:selectedEdge ?edge` +5. עבור כל קשר, קבל `tg:edge` (משולש מצוטט) ו-`tg:reasoning` +6. מצא סינתזה: `?synth prov:wasDerivedFrom ` +7. קבל את התשובה מ-`tg:document` דרך הספרן | +8. אם `--show-provenance`, עקוב אחר קשרים למסמכים מקוריים + +**דוגמה לפלט**: +``` +=== GraphRAG Session: urn:trustgraph:question:abc123 === + +Question: What was the War on Terror? +Time: 2024-01-15 10:30:00 + +--- Exploration --- +Retrieved 50 edges from knowledge graph + +--- Focus (Edge Selection) --- +Selected 12 edges: + + 1. (War on Terror, definition, "A military campaign...") + Reasoning: Directly defines the subject of the query + Source: chunk → page 2 → "Beyond the Vigilant State" + + 2. (Guantanamo Bay, part_of, War on Terror) + Reasoning: Shows key component of the campaign + +--- Synthesis --- +Answer: + The War on Terror was a military campaign initiated... + [truncated at 500 chars] +``` + +## קבצים ליצירה + +| קובץ | מטרה | +|------|---------| +| `trustgraph-cli/trustgraph/cli/show_document_hierarchy.py` | כלי 1 | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | כלי 2 | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | כלי 3 | + +## קבצים לשינוי + +| קובץ | שינוי | +|------|--------| +| `trustgraph-cli/setup.py` | הוספת רשומות ל-console_scripts | + +## הערות יישום + +1. **בטיחות תוכן בינארי**: נסה לפענח UTF-8; אם נכשל, הצג `[Binary: {size} bytes]` +2. **חיתוך**: שמור על `--max-content`/`--max-answer` עם מציין `[truncated]` +3. **משולשות מצוטטות**: נתח פורמט RDF-star מ-predicate `tg:edge` +4. **תבניות**: עקוב אחר תבניות CLI קיימות מ-`query_graph.py` + +## שיקולי אבטחה + +כל השאילתות מכבדות את גבולות המשתמש/אוסף +אימות טוקן נתמך באמצעות `--token` או `$TRUSTGRAPH_TOKEN` + +## אסטרטגיית בדיקה + +אימות ידני עם נתוני דוגמה: +```bash +# Load a test document +tg-load-pdf -f test.pdf -c test-collection + +# Verify hierarchy +tg-show-document-hierarchy "urn:trustgraph:doc:test" + +# Run a GraphRAG query with explainability +tg-invoke-graph-rag --explainable -q "Test question" + +# List and inspect traces +tg-list-explain-traces +tg-show-explain-trace "urn:trustgraph:question:xxx" +``` + +## הפניות + +הסבר בזמן שאילתה: `docs/tech-specs/query-time-explainability.md` +מקור בזמן חילוץ: `docs/tech-specs/extraction-time-provenance.md` +דוגמה קיימת של שורת פקודה: `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` diff --git a/docs/tech-specs/explainability-cli.hi.md b/docs/tech-specs/explainability-cli.hi.md new file mode 100644 index 00000000..130b44b1 --- /dev/null +++ b/docs/tech-specs/explainability-cli.hi.md @@ -0,0 +1,220 @@ +# व्याख्यात्मकता CLI तकनीकी विनिर्देश + +## स्थिति + +मसौदा + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ में व्याख्यात्मकता डेटा को डिबग और एक्सप्लोर करने के लिए CLI टूल का वर्णन करता है। ये उपकरण उपयोगकर्ताओं को यह ट्रैक करने में सक्षम बनाते हैं कि उत्तर कैसे प्राप्त किए गए और किनारा से वापस स्रोत दस्तावेजों तक उत्पत्ति श्रृंखला को डिबग किया गया। + +तीन CLI उपकरण: + +1. **`tg-show-document-hierarchy`** - दस्तावेज़ → पृष्ठ → भाग → किनारा पदानुक्रम दिखाएं +2. **`tg-list-explain-traces`** - सभी GraphRAG सत्रों को प्रश्नों के साथ सूचीबद्ध करें +3. **`tg-show-explain-trace`** - एक सत्र के लिए पूर्ण व्याख्यात्मकता ट्रेस दिखाएं + +## लक्ष्य + +**डीबगिंग**: डेवलपर्स को दस्तावेज़ प्रसंस्करण परिणामों का निरीक्षण करने में सक्षम करें +**लेखापरीक्षा**: किसी भी निकाले गए तथ्य को उसके स्रोत दस्तावेज़ तक ट्रैक करें +**पारदर्शिता**: सटीक रूप से दिखाएं कि GraphRAG ने उत्तर कैसे प्राप्त किया +**उपयोगिता**: समझदार डिफ़ॉल्ट के साथ सरल CLI इंटरफ़ेस + +## पृष्ठभूमि + +ट्रस्टग्राफ में दो उत्पत्ति प्रणालियाँ हैं: + +1. **निकालने के समय की उत्पत्ति** (देखें `extraction-time-provenance.md`): दस्तावेज़ → पृष्ठ → भाग → किनारा संबंधों को इनपुट के दौरान रिकॉर्ड करता है। `urn:graph:source` नामक ग्राफ में संग्रहीत, `prov:wasDerivedFrom` का उपयोग करके। + +2. **क्वेरी-टाइम व्याख्यात्मकता** (देखें `query-time-explainability.md`): GraphRAG प्रश्नों के दौरान प्रश्न → अन्वेषण → फोकस → संश्लेषण श्रृंखला को रिकॉर्ड करता है। `urn:graph:retrieval` नामक ग्राफ में संग्रहीत। + +वर्तमान सीमाएँ: +प्रसंस्करण के बाद दस्तावेज़ पदानुक्रम को देखने का कोई आसान तरीका नहीं है +व्याख्यात्मकता डेटा देखने के लिए ट्रिपल को मैन्युअल रूप से क्वेरी करना होगा +GraphRAG सत्र का कोई समेकित दृश्य नहीं है + +## तकनीकी डिज़ाइन + +### टूल 1: tg-show-document-hierarchy + +**उद्देश्य**: एक दस्तावेज़ आईडी को देखते हुए, सभी व्युत्पन्न संस्थाओं को पार करें और प्रदर्शित करें। + +**उपयोग**: +```bash +tg-show-document-hierarchy "urn:trustgraph:doc:abc123" +tg-show-document-hierarchy --show-content --max-content 500 "urn:trustgraph:doc:abc123" +``` + +**तर्क**: +| तर्क | विवरण | +|-----|-------------| +| `document_id` | दस्तावेज़ यूआरआई (स्थानिक) | +| `-u/--api-url` | गेटवे यूआरएल (डिफ़ॉल्ट: `$TRUSTGRAPH_URL`) | +| `-t/--token` | ऑथ टोकन (डिफ़ॉल्ट: `$TRUSTGRAPH_TOKEN`) | +| `-U/--user` | उपयोगकर्ता आईडी (डिफ़ॉल्ट: `trustgraph`) | +| `-C/--collection` | संग्रह (डिफ़ॉल्ट: `default`) | +| `--show-content` | ब्लॉब/दस्तावेज़ सामग्री शामिल करें | +| `--max-content` | प्रति ब्लॉब अधिकतम अक्षर (डिफ़ॉल्ट: 200) | +| `--format` | आउटपुट: `tree` (डिफ़ॉल्ट), `json` | + +**कार्यान्वयन**: +1. ट्रिपल क्वेरी करें: `?child prov:wasDerivedFrom ` in `urn:graph:source` +2. प्रत्येक परिणाम के बच्चों को पुनरावर्ती रूप से क्वेरी करें +3. ट्री संरचना बनाएं: दस्तावेज़ → पृष्ठ → भाग +4. यदि `--show-content`, तो लाइब्रेरियन एपीआई से सामग्री प्राप्त करें +5. इंडेंटेड ट्री या JSON के रूप में प्रदर्शित करें + +**आउटपुट उदाहरण**: +``` +Document: urn:trustgraph:doc:abc123 + Title: "Sample PDF" + Type: application/pdf + + └── Page 1: urn:trustgraph:doc:abc123/p1 + ├── Chunk 0: urn:trustgraph:doc:abc123/p1/c0 + │ Content: "The quick brown fox..." [truncated] + └── Chunk 1: urn:trustgraph:doc:abc123/p1/c1 + Content: "Machine learning is..." [truncated] +``` + +### टूल 2: tg-list-explain-traces + +**उद्देश्य**: एक संग्रह में सभी ग्राफ़आरएजी सत्रों (प्रश्नों) को सूचीबद्ध करना। + +**उपयोग**: +```bash +tg-list-explain-traces +tg-list-explain-traces --limit 20 --format json +``` + +**तर्क:** +| तर्क | विवरण | +|-----|-------------| +| `-u/--api-url` | गेटवे यूआरएल | +| `-t/--token` | प्रमाणीकरण टोकन | +| `-U/--user` | उपयोगकर्ता आईडी | +| `-C/--collection` | संग्रह | +| `--limit` | अधिकतम परिणाम (डिफ़ॉल्ट: 50) | +| `--format` | आउटपुट: `table` (डिफ़ॉल्ट), `json` | + +**कार्यान्वयन:** +1. क्वेरी: `?session tg:query ?text` को `urn:graph:retrieval` में | +2. क्वेरी टाइमस्टैम्प: `?session prov:startedAtTime ?time` | +3. तालिका के रूप में प्रदर्शित करें | + +**आउटपुट उदाहरण:** +``` +Session ID | Question | Time +----------------------------------------------|--------------------------------|--------------------- +urn:trustgraph:question:abc123 | What was the War on Terror? | 2024-01-15 10:30:00 +urn:trustgraph:question:def456 | Who founded OpenAI? | 2024-01-15 09:15:00 +``` + +### टूल 3: tg-show-explain-trace + +**उद्देश्य**: ग्राफ़आरएजी सत्र के लिए पूर्ण व्याख्या श्रृंखला प्रदर्शित करें। + +**उपयोग**: +```bash +tg-show-explain-trace "urn:trustgraph:question:abc123" +tg-show-explain-trace --max-answer 1000 --show-provenance "urn:trustgraph:question:abc123" +``` + +**तर्क:** +| तर्क | विवरण | +|-----|-------------| +| `question_id` | प्रश्न URI (स्थानिक) | +| `-u/--api-url` | गेटवे URL | +| `-t/--token` | प्रमाणीकरण टोकन | +| `-U/--user` | उपयोगकर्ता ID | +| `-C/--collection` | संग्रह | +| `--max-answer` | उत्तर के लिए अधिकतम अक्षर (डिफ़ॉल्ट: 500) | +| `--show-provenance` | स्रोत दस्तावेजों तक किनारों को ट्रेस करें | +| `--format` | आउटपुट: `text` (डिफ़ॉल्ट), `json` | + +**कार्यान्वयन:** +1. `tg:query` विधेय से प्रश्न पाठ प्राप्त करें। +2. अन्वेषण खोजें: `?exp prov:wasGeneratedBy ` +3. फोकस खोजें: `?focus prov:wasDerivedFrom ` +4. चयनित किनारों को प्राप्त करें: ` tg:selectedEdge ?edge` +5. प्रत्येक किनारे के लिए, `tg:edge` (उद्धृत ट्रिपल) और `tg:reasoning` प्राप्त करें। +6. संश्लेषण खोजें: `?synth prov:wasDerivedFrom ` +7. लाइब्रेरियन के माध्यम से `tg:document` से उत्तर प्राप्त करें। +8. यदि `--show-provenance`, तो स्रोत दस्तावेजों तक किनारों को ट्रेस करें। + +**आउटपुट उदाहरण:** +``` +=== GraphRAG Session: urn:trustgraph:question:abc123 === + +Question: What was the War on Terror? +Time: 2024-01-15 10:30:00 + +--- Exploration --- +Retrieved 50 edges from knowledge graph + +--- Focus (Edge Selection) --- +Selected 12 edges: + + 1. (War on Terror, definition, "A military campaign...") + Reasoning: Directly defines the subject of the query + Source: chunk → page 2 → "Beyond the Vigilant State" + + 2. (Guantanamo Bay, part_of, War on Terror) + Reasoning: Shows key component of the campaign + +--- Synthesis --- +Answer: + The War on Terror was a military campaign initiated... + [truncated at 500 chars] +``` + +## बनाने के लिए फ़ाइलें + +| फ़ाइल | उद्देश्य | +|------|---------| +| `trustgraph-cli/trustgraph/cli/show_document_hierarchy.py` | टूल 1 | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | टूल 2 | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | टूल 3 | + +## बदलने के लिए फ़ाइलें + +| फ़ाइल | परिवर्तन | +|------|--------| +| `trustgraph-cli/setup.py` | console_scripts प्रविष्टियाँ जोड़ें | + +## कार्यान्वयन नोट्स + +1. **बाइनरी सामग्री सुरक्षा**: UTF-8 डिकोड करने का प्रयास करें; यदि विफल रहता है, तो `[Binary: {size} bytes]` प्रदर्शित करें। +2. **छंटनी**: `--max-content`/`--max-answer` का सम्मान करें जिसमें `[truncated]` संकेतक हो। +3. **उद्धृत तिगुट**: `tg:edge` विधेय से RDF-स्टार प्रारूप को पार्स करें। +4. **पैटर्न**: `query_graph.py` से मौजूदा CLI पैटर्न का पालन करें। + +## सुरक्षा विचार + +सभी क्वेरी उपयोगकर्ता/संग्रह सीमाओं का सम्मान करती हैं। +`--token` या `$TRUSTGRAPH_TOKEN` के माध्यम से टोकन प्रमाणीकरण समर्थित है। + +## परीक्षण रणनीति + +नमूना डेटा के साथ मैन्युअल सत्यापन: +```bash +# Load a test document +tg-load-pdf -f test.pdf -c test-collection + +# Verify hierarchy +tg-show-document-hierarchy "urn:trustgraph:doc:test" + +# Run a GraphRAG query with explainability +tg-invoke-graph-rag --explainable -q "Test question" + +# List and inspect traces +tg-list-explain-traces +tg-show-explain-trace "urn:trustgraph:question:xxx" +``` + +## संदर्भ + +क्वेरी-टाइम व्याख्यात्मकता: `docs/tech-specs/query-time-explainability.md` +निष्कर्षण-टाइम उत्पत्ति: `docs/tech-specs/extraction-time-provenance.md` +मौजूदा CLI उदाहरण: `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` diff --git a/docs/tech-specs/explainability-cli.pt.md b/docs/tech-specs/explainability-cli.pt.md new file mode 100644 index 00000000..68d8c50c --- /dev/null +++ b/docs/tech-specs/explainability-cli.pt.md @@ -0,0 +1,220 @@ +# Especificação Técnica da Interface de Linha de Comando (CLI) para Explicabilidade + +## Status + +Rascunho + +## Visão Geral + +Esta especificação descreve ferramentas de linha de comando para depurar e explorar dados de explicabilidade no TrustGraph. Essas ferramentas permitem que os usuários rastreiem como as respostas foram derivadas e depurem a cadeia de origem desde as arestas até os documentos de origem. + +Três ferramentas de linha de comando: + +1. **`tg-show-document-hierarchy`** - Mostrar a hierarquia de documento → página → trecho → aresta +2. **`tg-list-explain-traces`** - Listar todas as sessões GraphRAG com perguntas +3. **`tg-show-explain-trace`** - Mostrar o rastreamento completo de explicabilidade para uma sessão + +## Objetivos + +**Depuração**: Permitir que os desenvolvedores inspecionem os resultados do processamento de documentos +**Auditabilidade**: Rastrear qualquer fato extraído de volta ao seu documento de origem +**Transparência**: Mostrar exatamente como o GraphRAG derivou uma resposta +**Usabilidade**: Interface de linha de comando simples com configurações padrão sensatas + +## Contexto + +O TrustGraph possui dois sistemas de rastreabilidade: + +1. **Rastreabilidade em tempo de extração** (veja `extraction-time-provenance.md`): Registra os relacionamentos de documento → página → trecho → aresta durante a ingestão. Armazenado em um grafo chamado `urn:graph:source` usando `prov:wasDerivedFrom`. + +2. **Explicabilidade em tempo de consulta** (veja `query-time-explainability.md`): Registra a cadeia de pergunta → exploração → foco → síntese durante as consultas GraphRAG. Armazenado em um grafo chamado `urn:graph:retrieval`. + +Limitações atuais: +Não há uma maneira fácil de visualizar a hierarquia de documentos após o processamento +É necessário consultar manualmente as triplas para ver os dados de explicabilidade +Não há uma visão consolidada de uma sessão GraphRAG + +## Design Técnico + +### Ferramenta 1: tg-show-document-hierarchy + +**Propósito**: Dado um ID de documento, percorrer e exibir todas as entidades derivadas. + +**Uso**: +```bash +tg-show-document-hierarchy "urn:trustgraph:doc:abc123" +tg-show-document-hierarchy --show-content --max-content 500 "urn:trustgraph:doc:abc123" +``` + +**Argumentos**: +| Arg | Descrição | +|-----|-------------| +| `document_id` | URI do documento (posicional) | +| `-u/--api-url` | URL do gateway (padrão: `$TRUSTGRAPH_URL`) | +| `-t/--token` | Token de autenticação (padrão: `$TRUSTGRAPH_TOKEN`) | +| `-U/--user` | ID do usuário (padrão: `trustgraph`) | +| `-C/--collection` | Coleção (padrão: `default`) | +| `--show-content` | Incluir conteúdo do blob/documento | +| `--max-content` | Máximo de caracteres por blob (padrão: 200) | +| `--format` | Saída: `tree` (padrão), `json` | + +**Implementação**: +1. Consultar triplas: `?child prov:wasDerivedFrom ` em `urn:graph:source` +2. Consultar recursivamente os filhos de cada resultado +3. Construir estrutura de árvore: Documento → Páginas → Blocos +4. Se `--show-content`, buscar conteúdo da API do bibliotecário +5. Exibir como árvore indentada ou JSON + +**Exemplo de Saída**: +``` +Document: urn:trustgraph:doc:abc123 + Title: "Sample PDF" + Type: application/pdf + + └── Page 1: urn:trustgraph:doc:abc123/p1 + ├── Chunk 0: urn:trustgraph:doc:abc123/p1/c0 + │ Content: "The quick brown fox..." [truncated] + └── Chunk 1: urn:trustgraph:doc:abc123/p1/c1 + Content: "Machine learning is..." [truncated] +``` + +### Ferramenta 2: tg-list-explain-traces + +**Propósito**: Listar todas as sessões (perguntas) do GraphRAG em uma coleção. + +**Uso**: +```bash +tg-list-explain-traces +tg-list-explain-traces --limit 20 --format json +``` + +**Argumentos**: +| Arg | Descrição | +|-----|-------------| +| `-u/--api-url` | URL do gateway | +| `-t/--token` | Token de autenticação | +| `-U/--user` | ID do usuário | +| `-C/--collection` | Coleção | +| `--limit` | Resultados máximos (padrão: 50) | +| `--format` | Saída: `table` (padrão), `json` | + +**Implementação**: +1. Consulta: `?session tg:query ?text` em `urn:graph:retrieval` +2. Consulta de carimbos de data/hora: `?session prov:startedAtTime ?time` +3. Exibir como tabela + +**Exemplo de Saída**: +``` +Session ID | Question | Time +----------------------------------------------|--------------------------------|--------------------- +urn:trustgraph:question:abc123 | What was the War on Terror? | 2024-01-15 10:30:00 +urn:trustgraph:question:def456 | Who founded OpenAI? | 2024-01-15 09:15:00 +``` + +### Ferramenta 3: tg-show-explain-trace + +**Propósito**: Mostrar a cascata completa de explicabilidade para uma sessão GraphRAG. + +**Uso**: +```bash +tg-show-explain-trace "urn:trustgraph:question:abc123" +tg-show-explain-trace --max-answer 1000 --show-provenance "urn:trustgraph:question:abc123" +``` + +**Argumentos**: +| Arg | Descrição | +|-----|-------------| +| `question_id` | URI da pergunta (posicional) | +| `-u/--api-url` | URL do gateway | +| `-t/--token` | Token de autenticação | +| `-U/--user` | ID do usuário | +| `-C/--collection` | Coleção | +| `--max-answer` | Número máximo de caracteres para a resposta (padrão: 500) | +| `--show-provenance` | Rastrear arestas para documentos de origem | +| `--format` | Saída: `text` (padrão), `json` | + +**Implementação**: +1. Obter o texto da pergunta do predicado `tg:query` +2. Encontrar a exploração: `?exp prov:wasGeneratedBy ` +3. Encontrar o foco: `?focus prov:wasDerivedFrom ` +4. Obter as arestas selecionadas: ` tg:selectedEdge ?edge` +5. Para cada aresta, obter `tg:edge` (tripla entre aspas) e `tg:reasoning` +6. Encontrar a síntese: `?synth prov:wasDerivedFrom ` +7. Obter a resposta de `tg:document` através do bibliotecário +8. Se `--show-provenance`, rastrear as arestas para os documentos de origem + +**Exemplo de Saída**: +``` +=== GraphRAG Session: urn:trustgraph:question:abc123 === + +Question: What was the War on Terror? +Time: 2024-01-15 10:30:00 + +--- Exploration --- +Retrieved 50 edges from knowledge graph + +--- Focus (Edge Selection) --- +Selected 12 edges: + + 1. (War on Terror, definition, "A military campaign...") + Reasoning: Directly defines the subject of the query + Source: chunk → page 2 → "Beyond the Vigilant State" + + 2. (Guantanamo Bay, part_of, War on Terror) + Reasoning: Shows key component of the campaign + +--- Synthesis --- +Answer: + The War on Terror was a military campaign initiated... + [truncated at 500 chars] +``` + +## Arquivos a Criar + +| Arquivo | Propósito | +|------|---------| +| `trustgraph-cli/trustgraph/cli/show_document_hierarchy.py` | Ferramenta 1 | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | Ferramenta 2 | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | Ferramenta 3 | + +## Arquivos a Modificar + +| Arquivo | Alteração | +|------|--------| +| `trustgraph-cli/setup.py` | Adicionar entradas de console_scripts | + +## Notas de Implementação + +1. **Segurança do conteúdo binário**: Tente decodificar UTF-8; se falhar, mostre `[Binary: {size} bytes]` +2. **Truncamento**: Respeite `--max-content`/`--max-answer` com indicador `[truncated]` +3. **Triplas entre aspas**: Analise o formato RDF-star a partir do predicado `tg:edge` +4. **Padrões**: Siga os padrões de CLI existentes a partir de `query_graph.py` + +## Considerações de Segurança + +Todas as consultas respeitam os limites de usuário/coleção +Autenticação por token suportada via `--token` ou `$TRUSTGRAPH_TOKEN` + +## Estratégia de Teste + +Verificação manual com dados de amostra: +```bash +# Load a test document +tg-load-pdf -f test.pdf -c test-collection + +# Verify hierarchy +tg-show-document-hierarchy "urn:trustgraph:doc:test" + +# Run a GraphRAG query with explainability +tg-invoke-graph-rag --explainable -q "Test question" + +# List and inspect traces +tg-list-explain-traces +tg-show-explain-trace "urn:trustgraph:question:xxx" +``` + +## Referências + +Explicabilidade em tempo de consulta: `docs/tech-specs/query-time-explainability.md` +Proveniência em tempo de extração: `docs/tech-specs/extraction-time-provenance.md` +Exemplo de CLI existente: `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` diff --git a/docs/tech-specs/explainability-cli.ru.md b/docs/tech-specs/explainability-cli.ru.md new file mode 100644 index 00000000..1c31458e --- /dev/null +++ b/docs/tech-specs/explainability-cli.ru.md @@ -0,0 +1,220 @@ +# Техническая спецификация CLI для Explainability + +## Статус + +Черновик + +## Обзор + +Эта спецификация описывает инструменты командной строки для отладки и изучения данных explainability в TrustGraph. Эти инструменты позволяют пользователям отслеживать, как были получены ответы, и отлаживать цепочку происхождения от ребер до исходных документов. + +Три инструмента командной строки: + +1. **`tg-show-document-hierarchy`** - Отображение иерархии документ → страница → фрагмент → ребро +2. **`tg-list-explain-traces`** - Список всех сессий GraphRAG с вопросами +3. **`tg-show-explain-trace`** - Отображение полной цепочки explainability для сессии + +## Цели + +**Отладка**: Предоставить разработчикам возможность просматривать результаты обработки документов. +**Прослеживаемость**: Отслеживать любой извлеченный факт до его исходного документа. +**Прозрачность**: Показать, как GraphRAG получил ответ. +**Удобство использования**: Простой интерфейс командной строки с разумными значениями по умолчанию. + +## Предыстория + +TrustGraph имеет две системы отслеживания происхождения: + +1. **Отслеживание происхождения во время извлечения** (см. `extraction-time-provenance.md`): Записывает отношения документ → страница → фрагмент → ребро во время импорта. Хранится в графе с именем `urn:graph:source`, используя `prov:wasDerivedFrom`. + +2. **Explainability во время запроса** (см. `query-time-explainability.md`): Записывает цепочку вопрос → исследование → фокус → синтез во время запросов GraphRAG. Хранится в графе с именем `urn:graph:retrieval`. + +Текущие ограничения: +Нет простого способа визуализации иерархии документов после обработки. +Необходимо вручную запрашивать тройки для просмотра данных explainability. +Нет единого представления сессии GraphRAG. + +## Технический дизайн + +### Инструмент 1: tg-show-document-hierarchy + +**Назначение**: При заданном идентификаторе документа, обходит и отображает все производные сущности. + +**Использование**: +```bash +tg-show-document-hierarchy "urn:trustgraph:doc:abc123" +tg-show-document-hierarchy --show-content --max-content 500 "urn:trustgraph:doc:abc123" +``` + +**Аргументы**: +| Аргумент | Описание | +|-----|-------------| +| `document_id` | URI документа (позиционный) | +| `-u/--api-url` | URL шлюза (по умолчанию: `$TRUSTGRAPH_URL`) | +| `-t/--token` | Токен авторизации (по умолчанию: `$TRUSTGRAPH_TOKEN`) | +| `-U/--user` | Идентификатор пользователя (по умолчанию: `trustgraph`) | +| `-C/--collection` | Коллекция (по умолчанию: `default`) | +| `--show-content` | Включить содержимое блоба/документа | +| `--max-content` | Максимальное количество символов на блоб (по умолчанию: 200) | +| `--format` | Вывод: `tree` (по умолчанию), `json` | + +**Реализация**: +1. Запрос троек: `?child prov:wasDerivedFrom ` в `urn:graph:source` +2. Рекурсивный запрос дочерних элементов каждого результата +3. Построение древовидной структуры: Документ → Страницы → Части +4. Если `--show-content`, получение содержимого из API librarian +5. Отображение в виде отформатированного дерева или JSON + +**Пример вывода**: +``` +Document: urn:trustgraph:doc:abc123 + Title: "Sample PDF" + Type: application/pdf + + └── Page 1: urn:trustgraph:doc:abc123/p1 + ├── Chunk 0: urn:trustgraph:doc:abc123/p1/c0 + │ Content: "The quick brown fox..." [truncated] + └── Chunk 1: urn:trustgraph:doc:abc123/p1/c1 + Content: "Machine learning is..." [truncated] +``` + +### Инструмент 2: tg-list-explain-traces + +**Назначение**: Вывести список всех сессий GraphRAG (вопросов) в коллекции. + +**Использование**: +```bash +tg-list-explain-traces +tg-list-explain-traces --limit 20 --format json +``` + +**Аргументы**: +| Аргумент | Описание | +|-----|-------------| +| `-u/--api-url` | URL шлюза | +| `-t/--token` | Токен авторизации | +| `-U/--user` | Идентификатор пользователя | +| `-C/--collection` | Коллекция | +| `--limit` | Максимальное количество результатов (по умолчанию: 50) | +| `--format` | Вывод: `table` (по умолчанию), `json` | + +**Реализация**: +1. Запрос: `?session tg:query ?text` в `urn:graph:retrieval` +2. Запрос временных меток: `?session prov:startedAtTime ?time` +3. Отображение в виде таблицы + +**Пример вывода**: +``` +Session ID | Question | Time +----------------------------------------------|--------------------------------|--------------------- +urn:trustgraph:question:abc123 | What was the War on Terror? | 2024-01-15 10:30:00 +urn:trustgraph:question:def456 | Who founded OpenAI? | 2024-01-15 09:15:00 +``` + +### Инструмент 3: tg-show-explain-trace + +**Назначение**: Отображение полной цепочки объяснений для сеанса GraphRAG. + +**Использование**: +```bash +tg-show-explain-trace "urn:trustgraph:question:abc123" +tg-show-explain-trace --max-answer 1000 --show-provenance "urn:trustgraph:question:abc123" +``` + +**Аргументы**: +| Аргумент | Описание | +|-----|-------------| +| `question_id` | URI вопроса (позиционный) | +| `-u/--api-url` | URL шлюза | +| `-t/--token` | Токен авторизации | +| `-U/--user` | Идентификатор пользователя | +| `-C/--collection` | Коллекция | +| `--max-answer` | Максимальное количество символов для ответа (по умолчанию: 500) | +| `--show-provenance` | Проследить связи к исходным документам | +| `--format` | Вывод: `text` (по умолчанию), `json` | + +**Реализация**: +1. Получить текст вопроса из предиката `tg:query` +2. Найти исследование: `?exp prov:wasGeneratedBy ` +3. Найти фокус: `?focus prov:wasDerivedFrom ` +4. Получить выбранные связи: ` tg:selectedEdge ?edge` +5. Для каждой связи, получить `tg:edge` (цитируемая тройка) и `tg:reasoning` +6. Найти синтез: `?synth prov:wasDerivedFrom ` +7. Получить ответ из `tg:document` через библиотекаря +8. Если `--show-provenance`, проследить связи к исходным документам + +**Пример вывода**: +``` +=== GraphRAG Session: urn:trustgraph:question:abc123 === + +Question: What was the War on Terror? +Time: 2024-01-15 10:30:00 + +--- Exploration --- +Retrieved 50 edges from knowledge graph + +--- Focus (Edge Selection) --- +Selected 12 edges: + + 1. (War on Terror, definition, "A military campaign...") + Reasoning: Directly defines the subject of the query + Source: chunk → page 2 → "Beyond the Vigilant State" + + 2. (Guantanamo Bay, part_of, War on Terror) + Reasoning: Shows key component of the campaign + +--- Synthesis --- +Answer: + The War on Terror was a military campaign initiated... + [truncated at 500 chars] +``` + +## Файлы для создания + +| Файл | Назначение | +|------|---------| +| `trustgraph-cli/trustgraph/cli/show_document_hierarchy.py` | Инструмент 1 | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | Инструмент 2 | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | Инструмент 3 | + +## Файлы для изменения + +| Файл | Изменение | +|------|--------| +| `trustgraph-cli/setup.py` | Добавить записи в console_scripts | + +## Замечания по реализации + +1. **Безопасность двоичного содержимого**: Попробуйте декодировать в UTF-8; если не удается, отобразите `[Binary: {size} bytes]`. +2. **Усечение**: Соблюдайте `--max-content`/`--max-answer` с индикатором `[truncated]`. +3. **Тройки в кавычках**: Разберите формат RDF-star из предиката `tg:edge`. +4. **Шаблоны**: Следуйте существующим шаблонам CLI из `query_graph.py`. + +## Вопросы безопасности + +Все запросы соответствуют границам пользователя/коллекции. +Поддерживается аутентификация по токену через `--token` или `$TRUSTGRAPH_TOKEN`. + +## Стратегия тестирования + +Ручная проверка с использованием образцовых данных: +```bash +# Load a test document +tg-load-pdf -f test.pdf -c test-collection + +# Verify hierarchy +tg-show-document-hierarchy "urn:trustgraph:doc:test" + +# Run a GraphRAG query with explainability +tg-invoke-graph-rag --explainable -q "Test question" + +# List and inspect traces +tg-list-explain-traces +tg-show-explain-trace "urn:trustgraph:question:xxx" +``` + +## Ссылки + +Объяснимость во время выполнения запроса: `docs/tech-specs/query-time-explainability.md` +Происхождение во время извлечения: `docs/tech-specs/extraction-time-provenance.md` +Существующий пример интерфейса командной строки: `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` diff --git a/docs/tech-specs/explainability-cli.sw.md b/docs/tech-specs/explainability-cli.sw.md new file mode 100644 index 00000000..f3644756 --- /dev/null +++ b/docs/tech-specs/explainability-cli.sw.md @@ -0,0 +1,220 @@ +# Maelezo ya Kiufundi ya Zana za Amri (CLI) za Ufafanuzi + +## Hali + +Rasimu + +## Muhtasari + +Maelezo haya yanaeleza zana za amri (CLI) za kuchanganua na kuchunguza data ya ufafanuzi katika TrustGraph. Zana hizi zinawawezesha watumiaji kufuatilia jinsi majibu yalivyopatikana na kuchanganua mnyororo wa asili kutoka kwa uhusiano (edges) hadi kwenye nyaraka za asili. + +Zana tatu za CLI: + +1. **`tg-show-document-hierarchy`** - Onyesha hierarkia ya nyaraka → kurasa → vipande → uhusiano +2. **`tg-list-explain-traces`** - Orodha ya vipindi vyote vya GraphRAG na maswali +3. **`tg-show-explain-trace`** - Onyesha mnyororo kamili wa ufafanuzi kwa kipindi + +## Lengo + +**Uchanganuzi**: Kuwawezesha watengenezaji kuchunguza matokeo ya usindikaji wa nyaraka +**Ufuatiliaji**: Kufuatilia ukweli wowote uliopatikana hadi kwenye nyaraka yake ya asili +**Unyonyaji**: Kuonyesha jinsi GraphRAG ilivyopata jibu +**Urahisi wa Matumizi**: Kiolesura rahisi cha CLI na mipangilio ya kawaida + +## Asili + +TrustGraph ina mifumo miwili ya asili: + +1. **Asili ya wakati wa uundaji** (angalia `extraction-time-provenance.md`): Inarecord uhusiano wa nyaraka → kurasa → vipande → uhusiano wakati wa kuingizwa. Hifadhiwa katika grafu iliyoitwa `urn:graph:source` kwa kutumia `prov:wasDerivedFrom`. + +2. **Ufafanuzi wa wakati wa kuulizia** (angalia `query-time-explainability.md`): Inarecord mnyororo wa swali → uchunguzi → umakini → muhtasari wakati wa maswali ya GraphRAG. Hifadhiwa katika grafu iliyoitwa `urn:graph:retrieval`. + +Mapungufu ya sasa: +Hakuna njia rahisi ya kuonyesha hierarkia ya nyaraka baada ya usindikaji +Lazima kuulize data ya ufafanuzi kwa kutumia triples +Hakuna mtazamo uliochanganywa wa kipindi cha GraphRAG + +## Muundo wa Kiufundi + +### Zana 1: tg-show-document-hierarchy + +**Lengo**: Ikiwa unapokea kitambulisho cha nyaraka, tembea na uonyeshe vitu vyote vilivyotokana. + +**Matumizi**: +```bash +tg-show-document-hierarchy "urn:trustgraph:doc:abc123" +tg-show-document-hierarchy --show-content --max-content 500 "urn:trustgraph:doc:abc123" +``` + +**Vigezo**: +| Arg | Maelezo | +|-----|-------------| +| `document_id` | URI ya hati (ya nafasi) | +| `-u/--api-url` | URL ya lango (ya kawaida: `$TRUSTGRAPH_URL`) | +| `-t/--token` | Ishara ya uthibitishaji (ya kawaida: `$TRUSTGRAPH_TOKEN`) | +| `-U/--user` | Kitambulisho cha mtumiaji (ya kawaida: `trustgraph`) | +| `-C/--collection` | Mkusanyiko (ya kawaida: `default`) | +| `--show-content` | Jumuisha yaliyomo katika faili/hati | +| `--max-content` | Herufi nyingi kwa kila faili (ya kawaida: 200) | +| `--format` | Matokeo: `tree` (ya kawaida), `json` | + +**Utendaji**: +1. Tafuta data: `?child prov:wasDerivedFrom ` katika `urn:graph:source` +2. Tafuta kwa urudi-urudi watoto wa kila matokeo +3. Jenga muundo wa mti: Hati → Kurasa → Sehemu +4. Ikiwa `--show-content`, pata yaliyomo kutoka kwa API ya msimamizi +5. Onyesha kama mti ulioainishwa au JSON + +**Mfano wa Matokeo**: +``` +Document: urn:trustgraph:doc:abc123 + Title: "Sample PDF" + Type: application/pdf + + └── Page 1: urn:trustgraph:doc:abc123/p1 + ├── Chunk 0: urn:trustgraph:doc:abc123/p1/c0 + │ Content: "The quick brown fox..." [truncated] + └── Chunk 1: urn:trustgraph:doc:abc123/p1/c1 + Content: "Machine learning is..." [truncated] +``` + +### Zana 2: tg-list-explain-traces + +**Madhumuni**: Kuorodhesha vipindi vyote vya GraphRAG (maswali) katika mkusanyiko. + +**Matumizi**: +```bash +tg-list-explain-traces +tg-list-explain-traces --limit 20 --format json +``` + +**Vigezo**: +| Arg | Maelezo | +|-----|-------------| +| `-u/--api-url` | URL ya lango | +| `-t/--token` | Token ya uthibitishaji | +| `-U/--user` | Kitambulisho cha mtumiaji | +| `-C/--collection` | Mkusanyiko | +| `--limit` | Matokeo ya juu (ya kawaida: 50) | +| `--format` | Matokeo: `table` (ya kawaida), `json` | + +**Utekelezaji**: +1. Uliza: `?session tg:query ?text` katika `urn:graph:retrieval` +2. Uliza alama za wakati: `?session prov:startedAtTime ?time` +3. Onyesha kama jedwali + +**Mfano wa Matokeo**: +``` +Session ID | Question | Time +----------------------------------------------|--------------------------------|--------------------- +urn:trustgraph:question:abc123 | What was the War on Terror? | 2024-01-15 10:30:00 +urn:trustgraph:question:def456 | Who founded OpenAI? | 2024-01-15 09:15:00 +``` + +### Zana 3: tg-show-explain-trace + +**Madhumuni**: Kuonyesha mnyororo kamili wa uelewaji kwa kipindi cha GraphRAG. + +**Matumizi**: +```bash +tg-show-explain-trace "urn:trustgraph:question:abc123" +tg-show-explain-trace --max-answer 1000 --show-provenance "urn:trustgraph:question:abc123" +``` + +**Vigezo**: +| Arg | Maelezo | +|-----|-------------| +| `question_id` | URI ya swali (nafasi) | +| `-u/--api-url` | URL ya lango | +| `-t/--token` | Ishara ya uthibitishaji | +| `-U/--user` | Kitambulisho cha mtumiaji | +| `-C/--collection` | Mkusanyiko | +| `--max-answer` | Idadi ya juu ya herufi kwa jibu (ya kawaida: 500) | +| `--show-provenance` | Fuatilia miunganisho hadi kwenye hati za asili | +| `--format` | Pato: `text` (ya kawaida), `json` | + +**Utendaji**: +1. Pata maandishi ya swali kutoka kwa `tg:query`. +2. Tafuta utafutaji: `?exp prov:wasGeneratedBy ` +3. Tafuta umakini: `?focus prov:wasDerivedFrom ` +4. Pata miunganisho iliyochaguliwa: ` tg:selectedEdge ?edge` +5. Kwa kila muunganisho, pata `tg:edge` (triple iliyotiwa mabano) na `tg:reasoning`. +6. Tafuta muhtasari: `?synth prov:wasDerivedFrom ` +7. Pata jibu kutoka kwa `tg:document` kupitia msimamizi wa maktaba. +8. Ikiwa `--show-provenance`, fuatilia miunganisho hadi kwenye hati za asili. + +**Mfano wa Pato**: +``` +=== GraphRAG Session: urn:trustgraph:question:abc123 === + +Question: What was the War on Terror? +Time: 2024-01-15 10:30:00 + +--- Exploration --- +Retrieved 50 edges from knowledge graph + +--- Focus (Edge Selection) --- +Selected 12 edges: + + 1. (War on Terror, definition, "A military campaign...") + Reasoning: Directly defines the subject of the query + Source: chunk → page 2 → "Beyond the Vigilant State" + + 2. (Guantanamo Bay, part_of, War on Terror) + Reasoning: Shows key component of the campaign + +--- Synthesis --- +Answer: + The War on Terror was a military campaign initiated... + [truncated at 500 chars] +``` + +## Faili Zinazotakazwa Kuundwa + +| Faili | Madhumuni | +|------|---------| +| `trustgraph-cli/trustgraph/cli/show_document_hierarchy.py` | Chombo 1 | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | Chombo 2 | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | Chombo 3 | + +## Faili Zinazotakazwa Kurekebishwa + +| Faili | Marekebisho | +|------|--------| +| `trustgraph-cli/setup.py` | Ongeza vipengele vya `console_scripts` | + +## Maelezo ya Utendaji + +1. **Usalama wa yaliyomo ya binary**: Jaribu kusimbua kwa UTF-8; ikiwa hufanikiwa, onyesha `[Binary: {size} bytes]` +2. **Ufupishaji**: Zifuata sheria za `--max-content`/`--max-answer` pamoja na ishara ya `[truncated]` +3. **Manuku matatu yaliyotiwa:** Changanua muundo wa RDF-star kutoka kwa `predicate` ya `tg:edge` +4. **Mifumo:** Fuata mifumo iliyopo ya CLI kutoka `query_graph.py` + +## Masuala ya Usalama + +Maswali yote yanazingatia mipaka ya mtumiaji/mkusanyiko +Uthibitishaji wa token unaoendeshwa kupitia `--token` au `$TRUSTGRAPH_TOKEN` + +## Mkakati wa Upimaji + +Uthibitisho wa mwongozo kwa data ya mfano: +```bash +# Load a test document +tg-load-pdf -f test.pdf -c test-collection + +# Verify hierarchy +tg-show-document-hierarchy "urn:trustgraph:doc:test" + +# Run a GraphRAG query with explainability +tg-invoke-graph-rag --explainable -q "Test question" + +# List and inspect traces +tg-list-explain-traces +tg-show-explain-trace "urn:trustgraph:question:xxx" +``` + +## Marejeleo + +Uwezekano wa kueleza matokeo wakati wa swali: `docs/tech-specs/query-time-explainability.md` +Chanzo cha data wakati wa uundaji: `docs/tech-specs/extraction-time-provenance.md` +Kifaa cha amri (CLI) cha mfano uliopo: `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` diff --git a/docs/tech-specs/explainability-cli.tr.md b/docs/tech-specs/explainability-cli.tr.md new file mode 100644 index 00000000..c73d351b --- /dev/null +++ b/docs/tech-specs/explainability-cli.tr.md @@ -0,0 +1,220 @@ +# Açıklanabilirlik CLI Teknik Özellikleri + +## Durum + +Taslak + +## Genel Bakış + +Bu özellik, TrustGraph'ta açıklanabilirlik verilerini hata ayıklamak ve incelemek için kullanılan CLI araçlarını tanımlar. Bu araçlar, kullanıcıların cevapların nasıl elde edildiğini izlemesini ve kenarlardan kaynak belgelere kadar olan köken zincirini hata ayıklamasını sağlar. + +Üç CLI aracı: + +1. **`tg-show-document-hierarchy`** - Belge → sayfa → parça → kenar hiyerarşisini gösterir +2. **`tg-list-explain-traces`** - Tüm GraphRAG oturumlarını sorularla birlikte listeler +3. **`tg-show-explain-trace`** - Bir oturum için tam açıklanabilirlik izini gösterir + +## Hedefler + +**Hata Ayıklama**: Geliştiricilerin belge işleme sonuçlarını incelemesini sağlar +**Denetlenebilirlik**: Herhangi bir çıkarılan gerçeği kaynak belgesine kadar izleme +**Şeffaflık**: GraphRAG'ın bir cevabı tam olarak nasıl elde ettiğini gösterme +**Kullanılabilirlik**: Akıllı varsayılanlarla basit bir CLI arayüzü + +## Arka Plan + +TrustGraph'un iki köken sistemi vardır: + +1. **Çıkarma zamanı kökeni** (bkz. `extraction-time-provenance.md`): Yükleme sırasında belge → sayfa → parça → kenar ilişkilerini kaydeder. `urn:graph:source` adlı grafte saklanır ve `prov:wasDerivedFrom` kullanılarak oluşturulur. + +2. **Sorgu zamanı açıklanabilirliği** (bkz. `query-time-explainability.md`): GraphRAG sorguları sırasında soru → keşif → odak → sentez zincirini kaydeder. `urn:graph:retrieval` adlı grafte saklanır. + +Mevcut sınırlamalar: +İşleme sonrası belge hiyerarşisini görselleştirmenin kolay bir yolu yok +Açıklanabilirlik verilerini görmek için üçlüleri manuel olarak sorgulamak gerekiyor +Bir GraphRAG oturumunun konsolide bir görünümü yok + +## Teknik Tasarım + +### Araç 1: tg-show-document-hierarchy + +**Amaç**: Bir belge kimliği verildiğinde, türetilen tüm varlıkları gezinerek ve görüntüleyerek. + +**Kullanım**: +```bash +tg-show-document-hierarchy "urn:trustgraph:doc:abc123" +tg-show-document-hierarchy --show-content --max-content 500 "urn:trustgraph:doc:abc123" +``` + +**Argümanlar**: +| Arg | Açıklama | +|-----|-------------| +| `document_id` | Belge URI'si (konumsal) | +| `-u/--api-url` | Ağ geçidi URL'si (varsayılan: `$TRUSTGRAPH_URL`) | +| `-t/--token` | Kimlik doğrulama belirteci (varsayılan: `$TRUSTGRAPH_TOKEN`) | +| `-U/--user` | Kullanıcı Kimliği (varsayılan: `trustgraph`) | +| `-C/--collection` | Koleksiyon (varsayılan: `default`) | +| `--show-content` | Blob/belge içeriğini dahil et | +| `--max-content` | Blob başına maksimum karakter sayısı (varsayılan: 200) | +| `--format` | Çıktı: `tree` (varsayılan), `json` | + +**Uygulama**: +1. Üçlüleri sorgula: `?child prov:wasDerivedFrom ` içinde `urn:graph:source` +2. Her sonucun çocuklarını yinelemeli olarak sorgula +3. Ağaç yapısını oluştur: Belge → Sayfalar → Parçalar +4. Eğer `--show-content` ise, içeriği kütüphaneci API'sinden al +5. Girintili bir ağaç veya JSON olarak göster + +**Çıktı Örneği**: +``` +Document: urn:trustgraph:doc:abc123 + Title: "Sample PDF" + Type: application/pdf + + └── Page 1: urn:trustgraph:doc:abc123/p1 + ├── Chunk 0: urn:trustgraph:doc:abc123/p1/c0 + │ Content: "The quick brown fox..." [truncated] + └── Chunk 1: urn:trustgraph:doc:abc123/p1/c1 + Content: "Machine learning is..." [truncated] +``` + +### Araç 2: tg-list-explain-traces + +**Amaç**: Bir koleksiyondaki tüm GraphRAG oturumlarını (soruları) listelemek. + +**Kullanım**: +```bash +tg-list-explain-traces +tg-list-explain-traces --limit 20 --format json +``` + +**Argümanlar**: +| Arg | Açıklama | +|-----|-------------| +| `-u/--api-url` | Ağ geçidi URL'si | +| `-t/--token` | Yetkilendirme belirteci | +| `-U/--user` | Kullanıcı Kimliği | +| `-C/--collection` | Koleksiyon | +| `--limit` | Maksimum sonuç sayısı (varsayılan: 50) | +| `--format` | Çıktı: `table` (varsayılan), `json` | + +**Uygulama**: +1. Sorgu: `?session tg:query ?text` içinde `urn:graph:retrieval` +2. Sorgu zaman damgaları: `?session prov:startedAtTime ?time` +3. Tablo olarak göster + +**Çıktı Örneği**: +``` +Session ID | Question | Time +----------------------------------------------|--------------------------------|--------------------- +urn:trustgraph:question:abc123 | What was the War on Terror? | 2024-01-15 10:30:00 +urn:trustgraph:question:def456 | Who founded OpenAI? | 2024-01-15 09:15:00 +``` + +### Araç 3: tg-show-explain-trace + +**Amaç**: Bir GraphRAG oturumu için tam açıklanabilirlik zincirini gösterir. + +**Kullanım**: +```bash +tg-show-explain-trace "urn:trustgraph:question:abc123" +tg-show-explain-trace --max-answer 1000 --show-provenance "urn:trustgraph:question:abc123" +``` + +**Argümanlar**: +| Arg | Açıklama | +|-----|-------------| +| `question_id` | Soru URI'si (konumsal) | +| `-u/--api-url` | Ağ geçidi URL'si | +| `-t/--token` | Kimlik doğrulama belirteci | +| `-U/--user` | Kullanıcı Kimliği | +| `-C/--collection` | Koleksiyon | +| `--max-answer` | Cevap için maksimum karakter sayısı (varsayılan: 500) | +| `--show-provenance` | Kaynak belgelere kadar kenarları izle | +| `--format` | Çıktı: `text` (varsayılan), `json` | + +**Uygulama**: +1. `tg:query` özniteliğinden soru metnini al. +2. Keşfi bul: `?exp prov:wasGeneratedBy ` +3. Odak noktasını bul: `?focus prov:wasDerivedFrom ` +4. Seçilen kenarları al: ` tg:selectedEdge ?edge` +5. Her kenar için, `tg:edge` (alıntılanmış üçlü) ve `tg:reasoning`'i al. +6. Sentezi bul: `?synth prov:wasDerivedFrom ` +7. Cevabı `tg:document` aracılığıyla kütüphaneciden al. +8. Eğer `--show-provenance` ise, kaynak belgelere kadar kenarları izle. + +**Çıktı Örneği**: +``` +=== GraphRAG Session: urn:trustgraph:question:abc123 === + +Question: What was the War on Terror? +Time: 2024-01-15 10:30:00 + +--- Exploration --- +Retrieved 50 edges from knowledge graph + +--- Focus (Edge Selection) --- +Selected 12 edges: + + 1. (War on Terror, definition, "A military campaign...") + Reasoning: Directly defines the subject of the query + Source: chunk → page 2 → "Beyond the Vigilant State" + + 2. (Guantanamo Bay, part_of, War on Terror) + Reasoning: Shows key component of the campaign + +--- Synthesis --- +Answer: + The War on Terror was a military campaign initiated... + [truncated at 500 chars] +``` + +## Oluşturulacak Dosyalar + +| Dosya | Amaç | +|------|---------| +| `trustgraph-cli/trustgraph/cli/show_document_hierarchy.py` | Araç 1 | +| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | Araç 2 | +| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | Araç 3 | + +## Değiştirilecek Dosyalar + +| Dosya | Değişiklik | +|------|--------| +| `trustgraph-cli/setup.py` | console_scripts girişlerini ekle | + +## Uygulama Notları + +1. **İkili içerik güvenliği**: UTF-8 ile çözmeyi deneyin; başarısız olursa `[Binary: {size} bytes]` gösterin. +2. **Kısaltma**: `--max-content`/`--max-answer` ile `[truncated]` göstergesine saygı gösterin. +3. **Tırnak işaretli üçlüler**: `tg:edge` önekinden RDF-star formatını ayrıştırın. +4. **Desenler**: `query_graph.py`'dan mevcut CLI desenlerini izleyin. + +## Güvenlik Hususları + +Tüm sorgular, kullanıcı/koleksiyon sınırlarına saygı gösterir. +`--token` veya `$TRUSTGRAPH_TOKEN` aracılığıyla token kimlik doğrulaması desteklenir. + +## Test Stratejisi + +Örnek verilerle manuel doğrulama: +```bash +# Load a test document +tg-load-pdf -f test.pdf -c test-collection + +# Verify hierarchy +tg-show-document-hierarchy "urn:trustgraph:doc:test" + +# Run a GraphRAG query with explainability +tg-invoke-graph-rag --explainable -q "Test question" + +# List and inspect traces +tg-list-explain-traces +tg-show-explain-trace "urn:trustgraph:question:xxx" +``` + +## Referanslar + +Sorgu zamanı açıklanabilirlik: `docs/tech-specs/query-time-explainability.md` +Çıkarım zamanı köken bilgisi: `docs/tech-specs/extraction-time-provenance.md` +Mevcut komut satırı örneği: `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` diff --git a/docs/tech-specs/extraction-flows.ar.md b/docs/tech-specs/extraction-flows.ar.md new file mode 100644 index 00000000..13409dbf --- /dev/null +++ b/docs/tech-specs/extraction-flows.ar.md @@ -0,0 +1,347 @@ +# تدفقات الاستخراج + +يصف هذا المستند كيفية تدفق البيانات عبر مسار الاستخراج الخاص بـ TrustGraph، بدءًا من تقديم المستندات وصولًا إلى تخزينها في مستودعات المعرفة. + +## نظرة عامة + +``` +┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐ +│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │ +│ │ │ (PDF only) │ │ │ │ Extraction │ +│ │────────────────────────▶│ │ │ │ +└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘ + │ │ + │ ├──▶ Triples + │ ├──▶ Entity Contexts + │ └──▶ Rows + │ + └──▶ Document Embeddings +``` + +## تخزين المحتوى + +### تخزين الكائنات (S3/Minio) + +يتم تخزين محتوى المستندات في تخزين الكائنات المتوافق مع S3: +تنسيق المسار: `doc/{object_id}` حيث object_id هو معرف فريد عالمي (UUID) +يتم تخزين جميع أنواع المستندات هنا: المستندات المصدر، الصفحات، الأجزاء + +### تخزين البيانات الوصفية (Cassandra) + +يتم تخزين البيانات الوصفية للمستندات في Cassandra وتشمل: +معرف المستند، العنوان، النوع (نوع MIME) +مرجع إلى تخزين الكائنات `object_id` +مرجع إلى المستندات الفرعية (الصفحات، الأجزاء) `parent_id` +`document_type`: "source"، "page"، "chunk"، "answer" + +### عتبة التضمين مقابل التدفق + +نقل المحتوى يستخدم استراتيجية تعتمد على الحجم: +**أقل من 2 ميجابايت**: يتم تضمين المحتوى مباشرة في الرسالة (مشفر بـ base64). +**أكبر من أو يساوي 2 ميجابايت**: يتم إرسال `document_id` فقط؛ يقوم المعالج باسترداد البيانات عبر واجهة برمجة التطبيقات الخاصة بالمكتبة. + +## المرحلة الأولى: تقديم المستند (المكتبة) + +### نقطة الدخول + +تدخل المستندات إلى النظام عبر عملية `add-document` الخاصة بالمكتبة: +1. يتم تحميل المحتوى إلى مساحة تخزين الكائنات. +2. يتم إنشاء سجل بيانات وصفية في Cassandra. +3. يتم إرجاع معرف المستند. + +### بدء عملية الاستخراج + +عملية `add-processing` تبدأ عملية الاستخراج: +تحدد `document_id`، و `flow` (معرف المسار)، و `collection` (مخزن الهدف). +تقوم عملية `load_document()` الخاصة بالمكتبة باسترداد المحتوى ونشره في قائمة انتظار الإدخال الخاصة بالتدفق. + +### المخطط: المستند + +``` +Document +├── metadata: Metadata +│ ├── id: str # Document identifier +│ ├── user: str # Tenant/user ID +│ ├── collection: str # Target collection +│ └── metadata: list[Triple] # (largely unused, historical) +├── data: bytes # PDF content (base64, if inline) +└── document_id: str # Librarian reference (if streaming) +``` + +**التوجيه:** بناءً على الحقل `kind`: +`application/pdf` → قائمة انتظار `document-load` → وحدة فك ترميز PDF +`text/plain` → قائمة انتظار `text-load` → وحدة تقسيم + +## المرحلة الثانية: وحدة فك ترميز PDF + +تحويل مستندات PDF إلى صفحات نصية. + +### العملية + +1. استرجاع المحتوى (مضمن في `data` أو عبر `document_id` من أمين المكتبة) +2. استخراج الصفحات باستخدام PyPDF +3. لكل صفحة: + حفظ كـ مستند فرعي في أمين المكتبة (`{doc_id}/p{page_num}`) + إرسال ثلاثيات المصدر (الصفحة مشتقة من المستند) + توجيه إلى وحدة التقسيم + +### المخطط: TextDocument + +``` +TextDocument +├── metadata: Metadata +│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1) +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── text: bytes # Page text content (if inline) +└── document_id: str # Librarian reference (e.g., "doc123/p1") +``` + +## المرحلة الثالثة: تقسيم النص إلى أجزاء + +يقسم النص إلى أجزاء عند الحجم المحدد. + +### المعلمات (قابلة للتكوين من خلال التدفق) + +`chunk_size`: الحجم المستهدف للجزء الواحد بالأحرف (الافتراضي: 2000) +`chunk_overlap`: التداخل بين الأجزاء (الافتراضي: 100) + +### العملية + +1. استرجاع محتوى النص (مباشرة أو عبر أمين المكتبة) +2. التقسيم باستخدام مقسم الأحرف التكراري +3. لكل جزء: + حفظ كوثيقة فرعية في أمين المكتبة (`{parent_id}/c{index}`) + إرسال بيانات المصدر (الجزء مشتق من صفحة/مستند) + توجيه إلى معالجات الاستخراج + +### المخطط: جزء + +``` +Chunk +├── metadata: Metadata +│ ├── id: str # Chunk URI +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── chunk: bytes # Chunk text content +└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3") +``` + +### التسلسل الهرمي لمعرف المستند + +تقوم المستندات الفرعية بتشفير أصلها في المعرف: +المصدر: `doc123` +الصفحة: `doc123/p5` +جزء من الصفحة: `doc123/p5/c2` +جزء من النص: `doc123/c2` + +## المرحلة 4: استخراج المعرفة + +تتوفر أنماط استخراج متعددة، يتم اختيارها بواسطة إعدادات التدفق. + +### النمط أ: GraphRAG الأساسي + +معالجتان متوازيتان: + +**kg-extract-definitions** +المدخلات: جزء +المخرجات: ثلاثيات (تعريفات الكيانات)، سياقات الكيانات +يستخرج: تسميات الكيانات، التعريفات + +**kg-extract-relationships** +المدخلات: جزء +المخرجات: ثلاثيات (علاقات)، سياقات الكيانات +يستخرج: علاقات الفاعل-الفعل-المفعول + +### النمط ب: مدفوع بالدلالات (kg-extract-ontology) + +المدخلات: جزء +المخرجات: ثلاثيات، سياقات الكيانات +يستخدم دلالات مُكوّنة لتوجيه الاستخراج + +### النمط ج: قائم على الوكيل (kg-extract-agent) + +المدخلات: جزء +المخرجات: ثلاثيات، سياقات الكيانات +يستخدم إطار عمل الوكيل للاستخراج + +### النمط د: استخراج الصفوف (kg-extract-rows) + +المدخلات: جزء +المخرجات: صفوف (بيانات منظمة، وليست ثلاثيات) +يستخدم تعريف المخطط لاستخراج سجلات منظمة + +### المخطط: ثلاثيات + +``` +Triples +├── metadata: Metadata +│ ├── id: str +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] # (set to [] by extractors) +└── triples: list[Triple] + └── Triple + ├── s: Term # Subject + ├── p: Term # Predicate + ├── o: Term # Object + └── g: str | None # Named graph +``` + +### المخطط: سياقات الكيانات + +``` +EntityContexts +├── metadata: Metadata +└── entities: list[EntityContext] + └── EntityContext + ├── entity: Term # Entity identifier (IRI) + ├── context: str # Textual description for embedding + └── chunk_id: str # Source chunk ID (provenance) +``` + +### المخطط: الصفوف + +``` +Rows +├── metadata: Metadata +├── row_schema: RowSchema +│ ├── name: str +│ ├── description: str +│ └── fields: list[Field] +└── rows: list[dict[str, str]] # Extracted records +``` + +## المرحلة الخامسة: توليد التضمينات + +### تضمينات الرسم البياني + +تحويل سياقات الكيانات إلى تضمينات متجهة. + +**العملية:** +1. استقبال سياقات الكيانات. +2. استدعاء خدمة التضمينات مع نص السياق. +3. إخراج تضمينات الرسم البياني (ت mapping بين الكيان والمتجه). + +**النموذج: تضمينات الرسم البياني** + +``` +GraphEmbeddings +├── metadata: Metadata +└── entities: list[EntityEmbeddings] + └── EntityEmbeddings + ├── entity: Term # Entity identifier + ├── vector: list[float] # Embedding vector + └── chunk_id: str # Source chunk (provenance) +``` + +### تضمينات المستندات + +يحول النص المقسم مباشرةً إلى تضمينات متجهة. + +**العملية:** +1. استقبال الجزء +2. استدعاء خدمة التضمينات باستخدام نص الجزء +3. إخراج تضمينات المستندات + +**التركيب: تضمينات المستندات** + +``` +DocumentEmbeddings +├── metadata: Metadata +└── chunks: list[ChunkEmbeddings] + └── ChunkEmbeddings + ├── chunk_id: str # Chunk identifier + └── vector: list[float] # Embedding vector +``` + +### تضمينات الصفوف + +تحويل حقول فهرس الصف إلى تضمينات متجهة. + +**العملية:** +1. استقبال الصفوف +2. تضمين حقول الفهرس المحددة +3. الإخراج إلى مخزن المتجهات الصفية + +## المرحلة 6: التخزين + +### مخزن ثلاثي + +يستقبل: ثلاثيات +التخزين: Cassandra (جداول تركز على الكيانات) +الرسوم البيانية المسماة تفصل المعرفة الأساسية عن المصادر: + `""` (افتراضي): حقائق المعرفة الأساسية + `urn:graph:source`: تتبع المصادر + `urn:graph:retrieval`: إمكانية الشرح في وقت الاستعلام + +### مخزن المتجهات (تضمينات الرسم البياني) + +يستقبل: تضمينات الرسم البياني +التخزين: Qdrant، Milvus، أو Pinecone +مفهرس بواسطة: IRI الكيان +البيانات الوصفية: chunk_id لتتبع المصادر + +### مخزن المتجهات (تضمينات المستندات) + +يستقبل: تضمينات المستندات +التخزين: Qdrant، Milvus، أو Pinecone +مفهرس بواسطة: chunk_id + +### مخزن الصفوف + +يستقبل: صفوف +التخزين: Cassandra +هيكل الجدول الموجه بالمخطط + +### مخزن المتجهات الصفية + +يستقبل: تضمينات الصفوف +التخزين: قاعدة بيانات المتجهات +مفهرس بواسطة: حقول فهرس الصف + +## تحليل حقول البيانات الوصفية + +### الحقول المستخدمة بنشاط + +| الحقل | الاستخدام | +|-------|-------| +| `metadata.id` | معرف المستند/الكتلة، التسجيل، تتبع المصادر | +| `metadata.user` | تعدد المستأجرين، توجيه التخزين | +| `metadata.collection` | اختيار المجموعة المستهدفة | +| `document_id` | مرجع أمين المكتبة، ربط تتبع المصادر | +| `chunk_id` | تتبع المصادر عبر مسار العمل | + +<<<<<<< HEAD +### الحقول التي قد تكون زائدة عن الحاجة + +| الحقل | الحالة | +|-------|--------| +| `metadata.metadata` | يتم تعيينه على `[]` بواسطة جميع المستخرجات؛ يتم التعامل مع بيانات وصفية على مستوى المستند الآن بواسطة أمين المكتبة في وقت الإرسال | +======= +### الحقول التي تمت إزالتها + +| الحقل | الحالة | +|-------|--------| +| `metadata.metadata` | تمت إزالته من الفئة `Metadata`. يتم الآن إرسال ثلاثيات البيانات الوصفية على مستوى المستند مباشرةً بواسطة أمين المكتبة إلى مخزن الثلاثيات في وقت الإرسال، ولا يتم نقلها عبر مسار العمل. | +>>>>>>> e3bcbf73 (قائمة البيانات الوصفية (الثلاثيات) في فئة مسار العمل Metadata) + +### نمط حقول البايت + +جميع حقول المحتوى (`data`، `text`، `chunk`) هي `bytes` ولكن يتم فك ترميزها على الفور إلى سلاسل UTF-8 بواسطة جميع المعالجات. لا يستخدم أي معالج بايت خام. + +## تكوين التدفق + +يتم تعريف التدفقات خارجيًا وتقديمها إلى أمين المكتبة عبر خدمة التكوين. يحدد كل تدفق: + +قوائم انتظار الإدخال (`text-load`، `document-load`) +سلسلة المعالجات +المعلمات (حجم الكتلة، طريقة الاستخراج، إلخ.) + +أمثلة على أنماط التدفق: +`pdf-graphrag`: PDF → Decoder → Chunker → Definitions + Relationships → Embeddings +`text-graphrag`: Text → Chunker → Definitions + Relationships → Embeddings +`pdf-ontology`: PDF → Decoder → Chunker → Ontology Extraction → Embeddings +`text-rows`: Text → Chunker → Row Extraction → Row Store diff --git a/docs/tech-specs/extraction-flows.es.md b/docs/tech-specs/extraction-flows.es.md new file mode 100644 index 00000000..20a8b580 --- /dev/null +++ b/docs/tech-specs/extraction-flows.es.md @@ -0,0 +1,347 @@ +# Flujos de extracción + +Este documento describe cómo los datos fluyen a través de la canalización de extracción de TrustGraph, desde la presentación del documento hasta el almacenamiento en almacenes de conocimiento. + +## Resumen + +``` +┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐ +│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │ +│ │ │ (PDF only) │ │ │ │ Extraction │ +│ │────────────────────────▶│ │ │ │ +└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘ + │ │ + │ ├──▶ Triples + │ ├──▶ Entity Contexts + │ └──▶ Rows + │ + └──▶ Document Embeddings +``` + +## Almacenamiento de contenido + +### Almacenamiento de objetos (S3/Minio) + +El contenido de los documentos se almacena en un almacenamiento de objetos compatible con S3: +Formato de la ruta: `doc/{object_id}` donde object_id es un UUID +Todos los tipos de documentos se almacenan aquí: documentos fuente, páginas, fragmentos + +### Almacenamiento de metadatos (Cassandra) + +Los metadatos de los documentos almacenados en Cassandra incluyen: +ID del documento, título, tipo (MIME) +Referencia al almacenamiento de objetos `object_id` +Referencia `parent_id` para documentos secundarios (páginas, fragmentos) +`document_type`: "fuente", "página", "fragmento", "respuesta" + +### Umbral de contenido en línea frente a transmisión + +La transmisión de contenido utiliza una estrategia basada en el tamaño: +**< 2MB**: El contenido se incluye directamente en el mensaje (codificado en base64) +**≥ 2MB**: Solo se envía `document_id`; el procesador recupera el contenido a través de la API del bibliotecario + +## Etapa 1: Envío de documentos (Bibliotecario) + +### Punto de entrada + +Los documentos ingresan al sistema a través de la operación `add-document` del bibliotecario: +1. El contenido se carga en el almacenamiento de objetos +2. Se crea un registro de metadatos en Cassandra +3. Devuelve el ID del documento + +### Activación de la extracción + +La operación `add-processing` activa la extracción: +Especifica `document_id`, `flow` (ID de la canalización), `collection` (almacén de destino) +La operación `load_document()` del bibliotecario recupera el contenido y lo publica en la cola de entrada del flujo + +### Esquema: Documento + +``` +Document +├── metadata: Metadata +│ ├── id: str # Document identifier +│ ├── user: str # Tenant/user ID +│ ├── collection: str # Target collection +│ └── metadata: list[Triple] # (largely unused, historical) +├── data: bytes # PDF content (base64, if inline) +└── document_id: str # Librarian reference (if streaming) +``` + +**Enrutamiento**: Basado en el campo `kind`: +`application/pdf` → cola `document-load` → Decodificador de PDF +`text/plain` → cola `text-load` → Fragmentador + +## Etapa 2: Decodificador de PDF + +Convierte documentos PDF en páginas de texto. + +### Proceso + +1. Obtener contenido (inline `data` o a través de `document_id` desde el bibliotecario) +2. Extraer páginas utilizando PyPDF +3. Para cada página: + Guardar como documento hijo en el bibliotecario (`{doc_id}/p{page_num}`) + Emitir triples de procedencia (página derivada del documento) + Enviar al fragmentador + +### Esquema: TextDocument + +``` +TextDocument +├── metadata: Metadata +│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1) +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── text: bytes # Page text content (if inline) +└── document_id: str # Librarian reference (e.g., "doc123/p1") +``` + +## Etapa 3: Fragmentador + +Divide el texto en fragmentos de un tamaño configurado. + +### Parámetros (configurables) + +`chunk_size`: Tamaño de fragmento objetivo en caracteres (predeterminado: 2000) +`chunk_overlap`: Solapamiento entre fragmentos (predeterminado: 100) + +### Proceso + +1. Obtener el contenido del texto (en línea o a través del bibliotecario) +2. Dividir utilizando un divisor de caracteres recursivo +3. Para cada fragmento: + Guardar como documento hijo en el bibliotecario (`{parent_id}/c{index}`) + Emitir triples de procedencia (fragmento derivado de página/documento) + Enviar a los procesadores de extracción + +### Esquema: Fragmento + +``` +Chunk +├── metadata: Metadata +│ ├── id: str # Chunk URI +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── chunk: bytes # Chunk text content +└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3") +``` + +### Jerarquía de Identificadores de Documentos + +Los documentos secundarios codifican su linaje en el identificador: +Fuente: `doc123` +Página: `doc123/p5` +Fragmento de página: `doc123/p5/c2` +Fragmento de texto: `doc123/c2` + +## Etapa 4: Extracción de Conocimiento + +Múltiples patrones de extracción disponibles, seleccionados por la configuración del flujo. + +### Patrón A: Basic GraphRAG + +Dos procesadores paralelos: + +**kg-extract-definitions** +Entrada: Fragmento +Salida: Triples (definiciones de entidades), EntityContexts +Extrae: etiquetas de entidades, definiciones + +**kg-extract-relationships** +Entrada: Fragmento +Salida: Triples (relaciones), EntityContexts +Extrae: relaciones sujeto-predicado-objeto + +### Patrón B: Basado en Ontología (kg-extract-ontology) + +Entrada: Fragmento +Salida: Triples, EntityContexts +Utiliza una ontología configurada para guiar la extracción + +### Patrón C: Basado en Agente (kg-extract-agent) + +Entrada: Fragmento +Salida: Triples, EntityContexts +Utiliza un marco de agente para la extracción + +### Patrón D: Extracción de Filas (kg-extract-rows) + +Entrada: Fragmento +Salida: Filas (datos estructurados, no triples) +Utiliza una definición de esquema para extraer registros estructurados + +### Esquema: Triples + +``` +Triples +├── metadata: Metadata +│ ├── id: str +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] # (set to [] by extractors) +└── triples: list[Triple] + └── Triple + ├── s: Term # Subject + ├── p: Term # Predicate + ├── o: Term # Object + └── g: str | None # Named graph +``` + +### Esquema: EntityContexts + +``` +EntityContexts +├── metadata: Metadata +└── entities: list[EntityContext] + └── EntityContext + ├── entity: Term # Entity identifier (IRI) + ├── context: str # Textual description for embedding + └── chunk_id: str # Source chunk ID (provenance) +``` + +### Esquema: Filas + +``` +Rows +├── metadata: Metadata +├── row_schema: RowSchema +│ ├── name: str +│ ├── description: str +│ └── fields: list[Field] +└── rows: list[dict[str, str]] # Extracted records +``` + +## Etapa 5: Generación de Incrustaciones (Embeddings) + +### Incrustaciones de Grafos (Graph Embeddings) + +Convierte los contextos de las entidades en incrustaciones vectoriales. + +**Proceso:** +1. Recibir EntityContexts (Contextos de Entidades) +2. Llamar al servicio de incrustaciones con el texto del contexto +3. Salida: GraphEmbeddings (mapeo de entidad a vector) + +**Esquema: GraphEmbeddings** + +``` +GraphEmbeddings +├── metadata: Metadata +└── entities: list[EntityEmbeddings] + └── EntityEmbeddings + ├── entity: Term # Entity identifier + ├── vector: list[float] # Embedding vector + └── chunk_id: str # Source chunk (provenance) +``` + +### Incrustaciones de documentos + +Convierte texto de fragmentos directamente en incrustaciones vectoriales. + +**Proceso:** +1. Recibir fragmento +2. Llamar al servicio de incrustaciones con el texto del fragmento +3. Salida: Incrustaciones de documentos + +**Esquema: Incrustaciones de documentos** + +``` +DocumentEmbeddings +├── metadata: Metadata +└── chunks: list[ChunkEmbeddings] + └── ChunkEmbeddings + ├── chunk_id: str # Chunk identifier + └── vector: list[float] # Embedding vector +``` + +### Incrustaciones de filas + +Convierte los campos de índice de fila en incrustaciones vectoriales. + +**Proceso:** +1. Recibir filas +2. Incrustar campos de índice configurados +3. Salida a la tienda de vectores de filas + +## Etapa 6: Almacenamiento + +### Triple Store + +Recibe: Triples +Almacenamiento: Cassandra (tablas centradas en entidades) +Los grafos con nombre separan el conocimiento central de la procedencia: + `""` (predeterminado): Hechos de conocimiento central + `urn:graph:source`: Procedencia de extracción + `urn:graph:retrieval`: Explicabilidad en tiempo de consulta + +### Tienda de vectores (Incrustaciones de grafos) + +Recibe: GraphEmbeddings +Almacenamiento: Qdrant, Milvus o Pinecone +Indexado por: IRI de entidad +Metadatos: chunk_id para la procedencia + +### Tienda de vectores (Incrustaciones de documentos) + +Recibe: DocumentEmbeddings +Almacenamiento: Qdrant, Milvus o Pinecone +Indexado por: chunk_id + +### Tienda de filas + +Recibe: Filas +Almacenamiento: Cassandra +Estructura de tabla basada en esquema + +### Tienda de vectores de filas + +Recibe: Incrustaciones de filas +Almacenamiento: Base de datos de vectores +Indexado por: Campos de índice de fila + +## Análisis de campos de metadatos + +### Campos utilizados activamente + +| Campo | Uso | +|-------|-------| +| `metadata.id` | Identificador de documento/fragmento, registro, procedencia | +| `metadata.user` | Multitenencia, enrutamiento de almacenamiento | +| `metadata.collection` | Selección de colección de destino | +| `document_id` | Referencia de bibliotecario, enlace de procedencia | +| `chunk_id` | Seguimiento de la procedencia a través de la canalización | + +<<<<<<< HEAD +### Campos potencialmente redundantes + +| Campo | Estado | +|-------|--------| +| `metadata.metadata` | Establecido en `[]` por todos los extractores; los metadatos a nivel de documento ahora se gestionan por el bibliotecario en el momento de la presentación | +======= +### Campos eliminados + +| Campo | Estado | +|-------|--------| +| `metadata.metadata` | Eliminado de la clase `Metadata`. Los triples de metadatos a nivel de documento ahora se emiten directamente por el bibliotecario a la triple store en el momento de la presentación, y no se transmiten a través de la canalización de extracción. | +>>>>>>> e3bcbf73 (The metadata field (list of triples) in the pipeline Metadata class) + +### Patrón de campos de bytes + +Todos los campos de contenido (`data`, `text`, `chunk`) son `bytes`, pero se decodifican inmediatamente a cadenas UTF-8 por todos los procesadores. Ningún procesador utiliza bytes sin procesar. + +## Configuración del flujo + +Los flujos se definen externamente y se proporcionan al bibliotecario a través del servicio de configuración. Cada flujo especifica: + +Colas de entrada (`text-load`, `document-load`) +Cadena de procesadores +Parámetros (tamaño del fragmento, método de extracción, etc.) + +Patrones de flujo de ejemplo: +`pdf-graphrag`: PDF → Decodificador → Fragmentador → Definiciones + Relaciones → Incrustaciones +`text-graphrag`: Texto → Fragmentador → Definiciones + Relaciones → Incrustaciones +`pdf-ontology`: PDF → Decodificador → Fragmentador → Extracción de ontología → Incrustaciones +`text-rows`: Texto → Fragmentador → Extracción de filas → Tienda de filas diff --git a/docs/tech-specs/extraction-flows.he.md b/docs/tech-specs/extraction-flows.he.md new file mode 100644 index 00000000..ba6bbd0d --- /dev/null +++ b/docs/tech-specs/extraction-flows.he.md @@ -0,0 +1,347 @@ +# זרימות חילוץ + +מסמך זה מתאר כיצד נתונים זורמים דרך צינור החילוץ של TrustGraph, החל מהגשת המסמכים ועד לאחסון במאגרי ידע. + +## סקירה כללית + +``` +┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐ +│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │ +│ │ │ (PDF only) │ │ │ │ Extraction │ +│ │────────────────────────▶│ │ │ │ +└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘ + │ │ + │ ├──▶ Triples + │ ├──▶ Entity Contexts + │ └──▶ Rows + │ + └──▶ Document Embeddings +``` + +## אחסון תוכן + +### אחסון בלובים (S3/Minio) + +תוכן מסמכים מאוחסן באחסון בלובים התואם ל-S3: +פורמט נתיב: `doc/{object_id}` כאשר object_id הוא מזהה UUID +כל סוגי המסמכים מאוחסנים כאן: מסמכים מקוריים, עמודים, חלקים + +### אחסון מטא-דאטה (Cassandra) + +מטא-דאטה של מסמכים המאוחסן ב-Cassandra כולל: +מזהה מסמך, כותרת, סוג (MIME type) +הפניה לאחסון הבלובים `object_id` +`parent_id` עבור מסמכים משניים (עמודים, חלקים) +`document_type`: "source", "page", "chunk", "answer" + +### סף בין הטמעה להזרמה + +העברת תוכן משתמשת באסטרטגיה המבוססת על גודל: +**פחות מ-2MB**: התוכן כלול בתוך ההודעה (מקודד ב-base64) +**גדול או שווה ל-2MB**: נשלח רק `document_id`; המעבד שולף דרך ממשק ה-librarian API + +## שלב 1: הגשת מסמך (Librarian) + +### נקודת כניסה + +מסמכים נכנסים למערכת דרך הפעולה `add-document` של ה-librarian: +1. התוכן מועלה לאחסון הבלובים +2. רשומה של מטא-דאטה נוצרת ב-Cassandra +3. מחזיר מזהה מסמך + +### הפעלת חילוץ + +הפעולה `add-processing` מפעילה חילוץ: +מציין `document_id`, `flow` (מזהה צינור), `collection` (מחסן יעד) +הפעולה `load_document()` של ה-librarian שולפת את התוכן ומפרסמת לתור הקלט של ה-flow + +### סכימה: מסמך + +``` +Document +├── metadata: Metadata +│ ├── id: str # Document identifier +│ ├── user: str # Tenant/user ID +│ ├── collection: str # Target collection +│ └── metadata: list[Triple] # (largely unused, historical) +├── data: bytes # PDF content (base64, if inline) +└── document_id: str # Librarian reference (if streaming) +``` + +**ניתוב:** בהתבסס על השדה `kind`: +`application/pdf` → תור `document-load` → מפענח PDF +`text/plain` → תור `text-load` → מפרק + +## שלב 2: מפענח PDF + +ממיר מסמכי PDF לעמודי טקסט. + +### תהליך + +1. שליפת תוכן (בשורת `data` או דרך `document_id` מהספרן) +2. חילוץ עמודים באמצעות PyPDF +3. עבור כל עמוד: + שמירה כמסמך משני בספרן (`{doc_id}/p{page_num}`) + שליחת טריפלים של מקור (עמוד שמקורו במסמך) + העברה למפרק + +### סכימה: TextDocument + +``` +TextDocument +├── metadata: Metadata +│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1) +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── text: bytes # Page text content (if inline) +└── document_id: str # Librarian reference (e.g., "doc123/p1") +``` + +## שלב 3: חלוקה לחלקים + +מחלק טקסט לחלקים בגודל מוגדר. + +### פרמטרים (ניתנים להגדרה בתוך זרימת העבודה) + +`chunk_size`: גודל החלק המיועד בתווים (ברירת מחדל: 2000) +`chunk_overlap`: חפיפה בין חלקים (ברירת מחדל: 100) + +### תהליך + +1. שליפת תוכן הטקסט (בשורת הקוד או דרך הספרן) +2. חלוקה באמצעות מפריד תווים רקורסיבי +3. עבור כל חלק: + שמירה כמסמך משני בספרן (`{parent_id}/c{index}`) + שליחת טריפלים של מקור (החלק נגזר מדף/מסמך) + העברה למעבדי חילוץ + +### סכימה: חלק + +``` +Chunk +├── metadata: Metadata +│ ├── id: str # Chunk URI +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── chunk: bytes # Chunk text content +└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3") +``` + +### היררכיית מזהי מסמכים + +מסמכים משניים מקודדים את שושלתם במזהה: +מקור: `doc123` +עמוד: `doc123/p5` +מקטע מעמוד: `doc123/p5/c2` +מקטע מטקסט: `doc123/c2` + +## שלב 4: חילוץ ידע + +קיימים דפוסי חילוץ מרובים, הנבחרים על ידי תצורת זרימת העבודה. + +### דפוס א': GraphRAG בסיסי + +שני מעבדים מקבילים: + +**kg-extract-definitions** +קלט: מקטע +פלט: משולשים (הגדרות ישויות), הקשרים של ישויות +מחלץ: תוויות ישויות, הגדרות + +**kg-extract-relationships** +קלט: מקטע +פלט: משולשים (יחסים), הקשרים של ישויות +מחלץ: יחסי נושא-נשוא-אובייקט + +### דפוס ב': מונחה אונטולוגיה (kg-extract-ontology) + +קלט: מקטע +פלט: משולשים, הקשרים של ישויות +משתמש באונטולוגיה מוגדרת כדי להנחות את החילוץ + +### דפוס ג': מבוסס סוכן (kg-extract-agent) + +קלט: מקטע +פלט: משולשים, הקשרים של ישויות +משתמש במסגרת סוכן לחילוץ + +### דפוס ד': חילוץ שורות (kg-extract-rows) + +קלט: מקטע +פלט: שורות (נתונים מובנים, לא משולשים) +משתמש בהגדרת סכימה כדי לחלץ רשומות מובנות + +### סכימה: משולשים + +``` +Triples +├── metadata: Metadata +│ ├── id: str +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] # (set to [] by extractors) +└── triples: list[Triple] + └── Triple + ├── s: Term # Subject + ├── p: Term # Predicate + ├── o: Term # Object + └── g: str | None # Named graph +``` + +### סכימה: EntityContexts + +``` +EntityContexts +├── metadata: Metadata +└── entities: list[EntityContext] + └── EntityContext + ├── entity: Term # Entity identifier (IRI) + ├── context: str # Textual description for embedding + └── chunk_id: str # Source chunk ID (provenance) +``` + +### סכימה: שורות + +``` +Rows +├── metadata: Metadata +├── row_schema: RowSchema +│ ├── name: str +│ ├── description: str +│ └── fields: list[Field] +└── rows: list[dict[str, str]] # Extracted records +``` + +## שלב 5: יצירת הטמעות (Embeddings) + +### הטמעות גרפיות (Graph Embeddings) + +ממיר הקשרים של ישויות להטמעות וקטוריות. + +**תהליך:** +1. קבלת הקשרים של ישויות (EntityContexts) +2. הפעלת שירות הטמעות עם טקסט ההקשר +3. פלט הטמעות גרפיות (מיפוי ישות ← וקטור) + +**סכימה: הטמעות גרפיות (GraphEmbeddings)** + +``` +GraphEmbeddings +├── metadata: Metadata +└── entities: list[EntityEmbeddings] + └── EntityEmbeddings + ├── entity: Term # Entity identifier + ├── vector: list[float] # Embedding vector + └── chunk_id: str # Source chunk (provenance) +``` + +### הטמעות מסמכים + +ממיר טקסט מחולק ישירות להטמעות וקטוריות. + +**תהליך:** +1. קבלת מקטע +2. הפעלת שירות הטמעות עם טקסט המקטע +3. פלט הטמעות מסמכים + +**סכימה: הטמעות מסמכים** + +``` +DocumentEmbeddings +├── metadata: Metadata +└── chunks: list[ChunkEmbeddings] + └── ChunkEmbeddings + ├── chunk_id: str # Chunk identifier + └── vector: list[float] # Embedding vector +``` + +### הטמעות שורות + +ממיר שדות אינדקס שורות להטמעות וקטוריות. + +**תהליך:** +1. קבלת שורות +2. הטמעת שדות אינדקס מוגדרים +3. פלט לאחסון וקטורים של שורות + +## שלב 6: אחסון + +### מאגר משולשות + +מקבל: משולשות +אחסון: Cassandra (טבלאות ממוקדות ישויות) +גרפים בעלי שמות מפרידים ידע ליבה ממידע על מקור: + `""` (ברירת מחדל): עובדות ידע ליבה + `urn:graph:source`: מידע על מקור החילוץ + `urn:graph:retrieval`: הסבר בזמן שאילתה + +### מאגר וקטורים (הטמעות גרפים) + +מקבל: הטמעות גרפים +אחסון: Qdrant, Milvus, או Pinecone +מאוּינדקס על ידי: IRI של ישות +מטא-דאטה: chunk_id עבור מידע על מקור + +### מאגר וקטורים (הטמעות מסמכים) + +מקבל: הטמעות מסמכים +אחסון: Qdrant, Milvus, או Pinecone +מאוּינדקס על ידי: chunk_id + +### מאגר שורות + +מקבל: שורות +אחסון: Cassandra +מבנה טבלאות המונחה סכימה + +### מאגר וקטורים של שורות + +מקבל: הטמעות שורות +אחסון: מסד נתונים וקטורי +מאוּנדקס על ידי: שדות אינדקס שורה + +## ניתוח שדות מטא-דאטה + +### שדות בשימוש פעיל + +| שדה | שימוש | +|-------|-------| +| `metadata.id` | מזהה מסמך/חלק, רישום, מקור +| `metadata.user` | ריבוי דיירים, ניתוב אחסון +| `metadata.collection` | בחירת אוסף יעד +| `document_id` | הפניה לספרן, קישור למקור +| `chunk_id` | מעקב אחר מקור לאורך הצינור + +<<<<<<< HEAD +### שדות שעלולים להיות מיותרים + +| שדה | סטטוס | +|-------|--------| +| `metadata.metadata` | מוגדר ל-`[]` על ידי כל המחלצים; מטא-דאטה ברמת המסמך מטופלים כעת על ידי הספרן בזמן ההגשה | +======= +### שדות שהוסרו + +| שדה | סטטוס | +|-------|--------| +| `metadata.metadata` | הוסר ממחלקת `Metadata`. משולשות מטא-דאטה ברמת המסמך משודרים כעת ישירות על ידי הספרן למאגר משולשות בזמן ההגשה, ולא מועברים דרך צינור החילוץ. | +>>>>>>> e3bcbf73 (The metadata field (list of triples) in the pipeline Metadata class) + +### תבניות שדות בייטים + +כל שדות התוכן (`data`, `text`, `chunk`) הם `bytes` אך מפענחים מיד לשרשורי UTF-8 על ידי כל המעבדים. אף מעבד לא משתמש בבייטים גולמיים. + +## תצורת זרימה + +זרימות מוגדרות מחוץ למערכת ומועברות לספרן באמצעות שירות התצורה. כל זרימה מציינת: + +תורי קלט (`text-load`, `document-load`) +שרשרת מעבדים +פרמטרים (גודל חתיכה, שיטת חילוץ, וכו') + +דוגמאות לתבניות זרימה: +`pdf-graphrag`: PDF → מפענח → חולק → הגדרות + קשרים → הטמעות +`text-graphrag`: טקסט → חולק → הגדרות + קשרים → הטמעות +`pdf-ontology`: PDF → מפענח → חולק → חילוץ אונטולוגיה → הטמעות +`text-rows`: טקסט → חולק → חילוץ שורות → אחסון שורות diff --git a/docs/tech-specs/extraction-flows.hi.md b/docs/tech-specs/extraction-flows.hi.md new file mode 100644 index 00000000..0ec61b5f --- /dev/null +++ b/docs/tech-specs/extraction-flows.hi.md @@ -0,0 +1,347 @@ +# निष्कर्षण प्रवाह (निकालने की प्रक्रियाएं) + +यह दस्तावेज़ बताता है कि डेटा ट्रस्टग्राफ निष्कर्षण पाइपलाइन के माध्यम से कैसे प्रवाहित होता है, दस्तावेज़ जमा करने से लेकर ज्ञान भंडारों में भंडारण तक। + +## अवलोकन + +``` +┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐ +│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │ +│ │ │ (PDF only) │ │ │ │ Extraction │ +│ │────────────────────────▶│ │ │ │ +└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘ + │ │ + │ ├──▶ Triples + │ ├──▶ Entity Contexts + │ └──▶ Rows + │ + └──▶ Document Embeddings +``` + +## सामग्री भंडारण + +### ब्लॉब भंडारण (S3/Minio) + +दस्तावेज़ सामग्री S3-संगत ब्लॉब भंडारण में संग्रहीत की जाती है: +पथ प्रारूप: `doc/{object_id}` जहाँ object_id एक UUID है +सभी दस्तावेज़ प्रकार यहां संग्रहीत किए जाते हैं: स्रोत दस्तावेज़, पृष्ठ, खंड + +### मेटाडेटा भंडारण (कैसेंड्रा) + +कैसेंड्रा में संग्रहीत दस्तावेज़ मेटाडेटा में शामिल हैं: +दस्तावेज़ आईडी, शीर्षक, प्रकार (MIME प्रकार) +ब्लॉब भंडारण के लिए `object_id` संदर्भ +चाइल्ड दस्तावेज़ों (पृष्ठों, खंडों) के लिए `parent_id` +`document_type`: "स्रोत", "पृष्ठ", "खंड", "उत्तर" + +### इनलाइन बनाम स्ट्रीमिंग थ्रेशोल्ड + +सामग्री प्रेषण एक आकार-आधारित रणनीति का उपयोग करता है: +**< 2MB**: सामग्री संदेश में इनलाइन शामिल है (base64-एन्कोडेड) +**≥ 2MB**: केवल `document_id` भेजा जाता है; प्रोसेसर लाइब्रेरियन API के माध्यम से प्राप्त करता है + +## चरण 1: दस्तावेज़ सबमिशन (लाइब्रेरियन) + +### प्रवेश बिंदु + +दस्तावेज़ लाइब्रेरियन के `add-document` ऑपरेशन के माध्यम से सिस्टम में प्रवेश करते हैं: +1. सामग्री को ब्लॉब भंडारण में अपलोड किया जाता है +2. कैसेंड्रा में मेटाडेटा रिकॉर्ड बनाया जाता है +3. दस्तावेज़ आईडी वापस करता है + +### निष्कर्षण को ट्रिगर करना + +`add-processing` ऑपरेशन निष्कर्षण को ट्रिगर करता है: +`document_id`, `flow` (पाइपलाइन आईडी), `collection` (लक्ष्य स्टोर) निर्दिष्ट करता है +लाइब्रेरियन का `load_document()` सामग्री प्राप्त करता है और फ्लो इनपुट कतार पर प्रकाशित करता है + +### स्कीमा: दस्तावेज़ + +``` +Document +├── metadata: Metadata +│ ├── id: str # Document identifier +│ ├── user: str # Tenant/user ID +│ ├── collection: str # Target collection +│ └── metadata: list[Triple] # (largely unused, historical) +├── data: bytes # PDF content (base64, if inline) +└── document_id: str # Librarian reference (if streaming) +``` + +**राउटिंग (Routing)**: `kind` फ़ील्ड के आधार पर: +`application/pdf` → `document-load` क्यू → पीडीएफ डिकोडर +`text/plain` → `text-load` क्यू → चंकर + +## चरण 2: पीडीएफ डिकोडर + +पीडीएफ दस्तावेजों को टेक्स्ट पृष्ठों में परिवर्तित करता है। + +### प्रक्रिया + +1. सामग्री प्राप्त करें (इनलाइन `data` या लाइब्रेरियन से `document_id` के माध्यम से) +2. PyPDF का उपयोग करके पृष्ठों को निकालें +3. प्रत्येक पृष्ठ के लिए: + लाइब्रेरियन में चाइल्ड दस्तावेज़ के रूप में सहेजें (`{doc_id}/p{page_num}`) + प्रामाणिकता ट्रिपल उत्सर्जित करें (पृष्ठ दस्तावेज़ से प्राप्त है) + चंकर को अग्रेषित करें + +### स्कीमा: TextDocument + +``` +TextDocument +├── metadata: Metadata +│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1) +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── text: bytes # Page text content (if inline) +└── document_id: str # Librarian reference (e.g., "doc123/p1") +``` + +## चरण 3: चंकर (Chunker) + +यह टेक्स्ट को कॉन्फ़िगर किए गए आकार में टुकड़ों में विभाजित करता है। + +### पैरामीटर (फ्लो-कॉन्फ़िगर करने योग्य) + +`chunk_size`: अक्षरों में लक्षित टुकड़ा आकार (डिफ़ॉल्ट: 2000) +`chunk_overlap`: टुकड़ों के बीच ओवरलैप (डिफ़ॉल्ट: 100) + +### प्रक्रिया + +1. टेक्स्ट सामग्री प्राप्त करें (इनलाइन या लाइब्रेरियन के माध्यम से) +2. रिकर्सिव कैरेक्टर स्प्लिटर का उपयोग करके विभाजित करें +3. प्रत्येक टुकड़े के लिए: + लाइब्रेरियन में चाइल्ड दस्तावेज़ के रूप में सहेजें (`{parent_id}/c{index}`) + प्रामाणिकता ट्रिपल उत्सर्जित करें (टुकड़ा पृष्ठ/दस्तावेज़ से प्राप्त हुआ है) + निष्कर्षण प्रोसेसर को अग्रेषित करें + +### स्कीमा: टुकड़ा (Chunk) + +``` +Chunk +├── metadata: Metadata +│ ├── id: str # Chunk URI +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── chunk: bytes # Chunk text content +└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3") +``` + +### दस्तावेज़ आईडी पदानुक्रम + +चाइल्ड दस्तावेज़ अपनी उत्पत्ति को आईडी में एन्कोड करते हैं: +स्रोत: `doc123` +पृष्ठ: `doc123/p5` +पृष्ठ से अंश: `doc123/p5/c2` +पाठ से अंश: `doc123/c2` + +## चरण 4: ज्ञान निष्कर्षण + +कई निष्कर्षण पैटर्न उपलब्ध हैं, जिन्हें प्रवाह कॉन्फ़िगरेशन द्वारा चुना जाता है। + +### पैटर्न ए: बेसिक ग्राफआरएजी + +दो समानांतर प्रोसेसर: + +**kg-extract-definitions** +इनपुट: अंश +आउटपुट: ट्रिपल (इकाई परिभाषाएँ), एंटिटीकॉन्टेक्स्ट +निष्कर्षण: इकाई लेबल, परिभाषाएँ + +**kg-extract-relationships** +इनपुट: अंश +आउटपुट: ट्रिपल (संबंध), एंटिटीकॉन्टेक्स्ट +निष्कर्षण: विषय-क्रिया-वस्तु संबंध + +### पैटर्न बी: ऑन्टोलॉजी-संचालित (kg-extract-ontology) + +इनपुट: अंश +आउटपुट: ट्रिपल, एंटिटीकॉन्टेक्स्ट +निष्कर्षण को निर्देशित करने के लिए कॉन्फ़िगर की गई ऑन्टोलॉजी का उपयोग करता है + +### पैटर्न सी: एजेंट-आधारित (kg-extract-agent) + +इनपुट: अंश +आउटपुट: ट्रिपल, एंटिटीकॉन्टेक्स्ट +निष्कर्षण के लिए एजेंट फ्रेमवर्क का उपयोग करता है + +### पैटर्न डी: पंक्ति निष्कर्षण (kg-extract-rows) + +इनपुट: अंश +आउटपुट: पंक्तियाँ (संरचित डेटा, ट्रिपल नहीं) +संरचित रिकॉर्ड निकालने के लिए स्कीमा परिभाषा का उपयोग करता है + +### स्कीमा: ट्रिपल + +``` +Triples +├── metadata: Metadata +│ ├── id: str +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] # (set to [] by extractors) +└── triples: list[Triple] + └── Triple + ├── s: Term # Subject + ├── p: Term # Predicate + ├── o: Term # Object + └── g: str | None # Named graph +``` + +### स्कीमा: एंटिटीकॉन्टेक्स्ट्स + +``` +EntityContexts +├── metadata: Metadata +└── entities: list[EntityContext] + └── EntityContext + ├── entity: Term # Entity identifier (IRI) + ├── context: str # Textual description for embedding + └── chunk_id: str # Source chunk ID (provenance) +``` + +### स्कीमा: पंक्तियाँ + +``` +Rows +├── metadata: Metadata +├── row_schema: RowSchema +│ ├── name: str +│ ├── description: str +│ └── fields: list[Field] +└── rows: list[dict[str, str]] # Extracted records +``` + +## चरण 5: एम्बेडिंग पीढ़ी + +### ग्राफ एम्बेडिंग + +इकाई संदर्भों को वेक्टर एम्बेडिंग में परिवर्तित करता है। + +**प्रक्रिया:** +1. इकाई संदर्भ प्राप्त करें +2. संदर्भ पाठ के साथ एम्बेडिंग सेवा को कॉल करें +3. ग्राफ एम्बेडिंग आउटपुट करें (इकाई → वेक्टर मैपिंग) + +**स्कीमा: ग्राफ एम्बेडिंग** + +``` +GraphEmbeddings +├── metadata: Metadata +└── entities: list[EntityEmbeddings] + └── EntityEmbeddings + ├── entity: Term # Entity identifier + ├── vector: list[float] # Embedding vector + └── chunk_id: str # Source chunk (provenance) +``` + +### दस्तावेज़ एम्बेडिंग + +यह सीधे टेक्स्ट के टुकड़ों को वेक्टर एम्बेडिंग में परिवर्तित करता है। + +**प्रक्रिया:** +1. टेक्स्ट का टुकड़ा प्राप्त करें +2. टेक्स्ट के टुकड़े के साथ एम्बेडिंग सेवा को कॉल करें +3. दस्तावेज़एम्बेडिंग आउटपुट करें + +**स्कीमा: दस्तावेज़एम्बेडिंग** + +``` +DocumentEmbeddings +├── metadata: Metadata +└── chunks: list[ChunkEmbeddings] + └── ChunkEmbeddings + ├── chunk_id: str # Chunk identifier + └── vector: list[float] # Embedding vector +``` + +### पंक्ति एम्बेडिंग (पंक्ति एम्बेडिंग) + +पंक्ति अनुक्रमणिका फ़ील्ड को वेक्टर एम्बेडिंग में परिवर्तित करता है। + +**प्रक्रिया:** +1. पंक्तियों को प्राप्त करें +2. कॉन्फ़िगर की गई अनुक्रमणिका फ़ील्ड को एम्बेड करें +3. पंक्ति वेक्टर स्टोर पर आउटपुट करें + +## चरण 6: भंडारण (चरण 6: भंडारण) + +### ट्रिपल स्टोर (ट्रिपल स्टोर) + +प्राप्त करता है: ट्रिपल (प्राप्त करता है: ट्रिपल) +भंडारण: कैसेंड्रा (इकाई-केंद्रित तालिकाएँ) (भंडारण: कैसेंड्रा (इकाई-केंद्रित तालिकाएँ)) +नामित ग्राफ मूल ज्ञान को उत्पत्ति से अलग करते हैं: (नामित ग्राफ मूल ज्ञान को उत्पत्ति से अलग करते हैं:) + `""` (डिफ़ॉल्ट): मूल ज्ञान तथ्य (डिफ़ॉल्ट: मूल ज्ञान तथ्य) + `urn:graph:source`: निष्कर्षण उत्पत्ति (निष्कर्षण उत्पत्ति) + `urn:graph:retrieval`: क्वेरी-टाइम व्याख्या (क्वेरी-टाइम व्याख्या) + +### वेक्टर स्टोर (ग्राफ एम्बेडिंग) (वेक्टर स्टोर (ग्राफ एम्बेडिंग)) + +प्राप्त करता है: GraphEmbeddings (प्राप्त करता है: GraphEmbeddings) +भंडारण: Qdrant, Milvus, या Pinecone (भंडारण: Qdrant, Milvus, या Pinecone) +अनुक्रमित: इकाई IRI द्वारा (अनुक्रमित: इकाई IRI द्वारा) +मेटाडेटा: उत्पत्ति के लिए chunk_id (मेटाडेटा: उत्पत्ति के लिए chunk_id) + +### वेक्टर स्टोर (दस्तावेज़ एम्बेडिंग) (वेक्टर स्टोर (दस्तावेज़ एम्बेडिंग)) + +प्राप्त करता है: DocumentEmbeddings (प्राप्त करता है: DocumentEmbeddings) +भंडारण: Qdrant, Milvus, या Pinecone (भंडारण: Qdrant, Milvus, या Pinecone) +अनुक्रमित: chunk_id द्वारा (अनुक्रमित: chunk_id द्वारा) + +### पंक्ति स्टोर (पंक्ति स्टोर) + +प्राप्त करता है: Rows (प्राप्त करता है: Rows) +भंडारण: कैसेंड्रा (भंडारण: कैसेंड्रा) +स्कीमा-संचालित तालिका संरचना (स्कीमा-संचालित तालिका संरचना) + +### पंक्ति वेक्टर स्टोर (पंक्ति वेक्टर स्टोर) + +प्राप्त होता है: पंक्ति एम्बेडिंग (पंक्ति एम्बेडिंग) +भंडारण: वेक्टर डेटाबेस (वेक्टर डेटाबेस) +अनुक्रमित किया गया: पंक्ति अनुक्रमणिका फ़ील्ड द्वारा (पंक्ति अनुक्रमणिका फ़ील्ड द्वारा) + +## मेटाडेटा फ़ील्ड विश्लेषण (मेटाडेटा फ़ील्ड विश्लेषण) + +### सक्रिय रूप से उपयोग किए जाने वाले फ़ील्ड (सक्रिय रूप से उपयोग किए जाने वाले फ़ील्ड) + +| फ़ील्ड | उपयोग | +|-------|-------| +| `metadata.id` | दस्तावेज़/चंक पहचानकर्ता, लॉगिंग, उत्पत्ति (दस्तावेज़/चंक पहचानकर्ता, लॉगिंग, उत्पत्ति) +| `metadata.user` | मल्टी-टेनेंसी, स्टोरेज रूटिंग (मल्टी-टेनेंसी, स्टोरेज रूटिंग) +| `metadata.collection` | लक्ष्य संग्रह चयन (लक्ष्य संग्रह चयन) +| `document_id` | लाइब्रेरियन संदर्भ, उत्पत्ति लिंकिंग (लाइब्रेरियन संदर्भ, उत्पत्ति लिंकिंग) +| `chunk_id` | पाइपलाइन के माध्यम से उत्पत्ति ट्रैकिंग (पाइपलाइन के माध्यम से उत्पत्ति ट्रैकिंग) + +<<<<<<< HEAD +### संभावित रूप से अनावश्यक फ़ील्ड (संभावित रूप से अनावश्यक फ़ील्ड) + +| फ़ील्ड | स्थिति | +|-------|--------| +| `metadata.metadata` | सभी एक्सट्रैक्टरों द्वारा `[]` पर सेट; दस्तावेज़-स्तरीय मेटाडेटा अब सबमिशन के समय लाइब्रेरियन द्वारा संभाला जाता है (सभी एक्सट्रैक्टरों द्वारा `[]` पर सेट; दस्तावेज़-स्तरीय मेटाडेटा अब सबमिशन के समय लाइब्रेरियन द्वारा संभाला जाता है) +======= +### हटाए गए फ़ील्ड (हटाए गए फ़ील्ड) + +| फ़ील्ड | स्थिति | +|-------|--------| +| `metadata.metadata` | `Metadata` वर्ग से हटा दिया गया। दस्तावेज़-स्तरीय मेटाडेटा ट्रिपल अब सीधे लाइब्रेरियन द्वारा ट्रिपल स्टोर को सबमिशन के समय भेजा जाता है, न कि निष्कर्षण पाइपलाइन के माध्यम से (`Metadata` वर्ग से हटा दिया गया। दस्तावेज़-स्तरीय मेटाडेटा ट्रिपल अब सीधे लाइब्रेरियन द्वारा ट्रिपल स्टोर को सबमिशन के समय भेजा जाता है, न कि निष्कर्षण पाइपलाइन के माध्यम से) +>>>>>>> e3bcbf73 (The metadata field (list of triples) in the pipeline Metadata class) + +### बाइट्स फ़ील्ड पैटर्न (बाइट्स फ़ील्ड पैटर्न) + +सभी सामग्री फ़ील्ड (`data`, `text`, `chunk`) `bytes` हैं लेकिन सभी प्रोसेसरों द्वारा तुरंत UTF-8 स्ट्रिंग में डिकोड किए जाते हैं। कोई भी प्रोसेसर कच्चे बाइट्स का उपयोग नहीं करता है। + +## फ्लो कॉन्फ़िगरेशन (फ्लो कॉन्फ़िगरेशन) + +फ्लो बाहरी रूप से परिभाषित किए जाते हैं और कॉन्फ़िगरेशन सेवा के माध्यम से लाइब्रेरियन को प्रदान किए जाते हैं। प्रत्येक फ्लो में निम्नलिखित निर्दिष्ट होता है: + +इनपुट क्यू (इनपुट क्यू) (`text-load`, `document-load`) +प्रोसेसर श्रृंखला (प्रोसेसर श्रृंखला) +पैरामीटर (चंक आकार, निष्कर्षण विधि, आदि) (पैरामीटर (चंक आकार, निष्कर्षण विधि, आदि)) + +फ्लो पैटर्न के उदाहरण: (फ्लो पैटर्न के उदाहरण:) +`pdf-graphrag`: PDF → Decoder → Chunker → Definitions + Relationships → Embeddings +`text-graphrag`: Text → Chunker → Definitions + Relationships → Embeddings +`pdf-ontology`: PDF → Decoder → Chunker → Ontology Extraction → Embeddings +`text-rows`: Text → Chunker → Row Extraction → Row Store diff --git a/docs/tech-specs/extraction-flows.pt.md b/docs/tech-specs/extraction-flows.pt.md new file mode 100644 index 00000000..b07dd5ac --- /dev/null +++ b/docs/tech-specs/extraction-flows.pt.md @@ -0,0 +1,347 @@ +# Fluxos de Extração + +Este documento descreve como os dados fluem através do pipeline de extração do TrustGraph, desde o envio do documento até ao armazenamento nos repositórios de conhecimento. + +## Visão Geral + +``` +┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐ +│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │ +│ │ │ (PDF only) │ │ │ │ Extraction │ +│ │────────────────────────▶│ │ │ │ +└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘ + │ │ + │ ├──▶ Triples + │ ├──▶ Entity Contexts + │ └──▶ Rows + │ + └──▶ Document Embeddings +``` + +## Armazenamento de Conteúdo + +### Armazenamento de Blobs (S3/Minio) + +O conteúdo do documento é armazenado em armazenamento de blobs compatível com S3: +Formato do caminho: `doc/{object_id}`, onde object_id é um UUID +Todos os tipos de documentos armazenados aqui: documentos de origem, páginas, trechos + +### Armazenamento de Metadados (Cassandra) + +Os metadados do documento armazenados no Cassandra incluem: +ID do documento, título, tipo (MIME) +Referência ao armazenamento de blobs `object_id` +Referência `parent_id` para documentos filhos (páginas, trechos) +`document_type`: "source", "page", "chunk", "answer" + +### Limiar de Incorporação vs. Streaming + +A transmissão de conteúdo usa uma estratégia baseada no tamanho: +**< 2MB**: O conteúdo é incluído inline na mensagem (codificado em base64) +**≥ 2MB**: Apenas `document_id` é enviado; o processador busca via API do bibliotecário + +## Etapa 1: Envio de Documento (Bibliotecário) + +### Ponto de Entrada + +Os documentos entram no sistema através da operação `add-document` do bibliotecário: +1. O conteúdo é carregado no armazenamento de blobs +2. Um registro de metadados é criado no Cassandra +3. Retorna o ID do documento + +### Disparando a Extração + +A operação `add-processing` dispara a extração: +Especifica `document_id`, `flow` (ID do pipeline), `collection` (loja de destino) +A operação `load_document()` do bibliotecário busca o conteúdo e o publica na fila de entrada do fluxo + +### Esquema: Documento + +``` +Document +├── metadata: Metadata +│ ├── id: str # Document identifier +│ ├── user: str # Tenant/user ID +│ ├── collection: str # Target collection +│ └── metadata: list[Triple] # (largely unused, historical) +├── data: bytes # PDF content (base64, if inline) +└── document_id: str # Librarian reference (if streaming) +``` + +**Roteamento**: Baseado no campo `kind`: +`application/pdf` → fila `document-load` → Decodificador PDF +`text/plain` → fila `text-load` → Fragmentador + +## Etapa 2: Decodificador PDF + +Converte documentos PDF em páginas de texto. + +### Processo + +1. Buscar conteúdo (inline `data` ou via `document_id` do bibliotecário) +2. Extrair páginas usando PyPDF +3. Para cada página: + Salvar como documento filho no bibliotecário (`{doc_id}/p{page_num}`) + Emitir triplas de procedência (página derivada do documento) + Enviar para o fragmentador + +### Esquema: TextDocument + +``` +TextDocument +├── metadata: Metadata +│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1) +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── text: bytes # Page text content (if inline) +└── document_id: str # Librarian reference (e.g., "doc123/p1") +``` + +## Etapa 3: Divisor em Blocos + +Divide o texto em blocos de tamanho configurado. + +### Parâmetros (configuráveis no fluxo) + +`chunk_size`: Tamanho do bloco alvo em caracteres (padrão: 2000) +`chunk_overlap`: Sobreposição entre blocos (padrão: 100) + +### Processo + +1. Buscar o conteúdo do texto (inline ou via bibliotecário) +2. Dividir usando o divisor de caracteres recursivo +3. Para cada bloco: + Salvar como documento filho no bibliotecário (`{parent_id}/c{index}`) + Emitir triplas de procedência (bloco derivado da página/documento) + Encaminhar para os processadores de extração + +### Esquema: Bloco + +``` +Chunk +├── metadata: Metadata +│ ├── id: str # Chunk URI +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── chunk: bytes # Chunk text content +└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3") +``` + +### Hierarquia de Identificação de Documentos + +Documentos filhos codificam sua linhagem no ID: +Fonte: `doc123` +Página: `doc123/p5` +Trecho da página: `doc123/p5/c2` +Trecho de texto: `doc123/c2` + +## Etapa 4: Extração de Conhecimento + +Múltiplos padrões de extração disponíveis, selecionados pela configuração do fluxo. + +### Padrão A: Basic GraphRAG + +Dois processadores paralelos: + +**kg-extract-definitions** +Entrada: Trecho +Saída: Triplas (definições de entidades), Contextos de Entidade +Extrai: rótulos de entidades, definições + +**kg-extract-relationships** +Entrada: Trecho +Saída: Triplas (relacionamentos), Contextos de Entidade +Extrai: relações sujeito-predicado-objeto + +### Padrão B: Orientado a Ontologia (kg-extract-ontology) + +Entrada: Trecho +Saída: Triplas, Contextos de Entidade +Utiliza uma ontologia configurada para guiar a extração + +### Padrão C: Baseado em Agente (kg-extract-agent) + +Entrada: Trecho +Saída: Triplas, Contextos de Entidade +Utiliza um framework de agente para a extração + +### Padrão D: Extração de Linhas (kg-extract-rows) + +Entrada: Trecho +Saída: Linhas (dados estruturados, não triplas) +Utiliza uma definição de esquema para extrair registros estruturados + +### Esquema: Triplas + +``` +Triples +├── metadata: Metadata +│ ├── id: str +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] # (set to [] by extractors) +└── triples: list[Triple] + └── Triple + ├── s: Term # Subject + ├── p: Term # Predicate + ├── o: Term # Object + └── g: str | None # Named graph +``` + +### Esquema: EntityContexts + +``` +EntityContexts +├── metadata: Metadata +└── entities: list[EntityContext] + └── EntityContext + ├── entity: Term # Entity identifier (IRI) + ├── context: str # Textual description for embedding + └── chunk_id: str # Source chunk ID (provenance) +``` + +### Esquema: Linhas + +``` +Rows +├── metadata: Metadata +├── row_schema: RowSchema +│ ├── name: str +│ ├── description: str +│ └── fields: list[Field] +└── rows: list[dict[str, str]] # Extracted records +``` + +## Etapa 5: Geração de Embeddings + +### Embeddings de Grafos + +Converte contextos de entidades em embeddings vetoriais. + +**Processo:** +1. Receber EntityContexts +2. Chamar o serviço de embeddings com o texto do contexto +3. Output GraphEmbeddings (mapeamento de entidade para vetor) + +**Esquema: GraphEmbeddings** + +``` +GraphEmbeddings +├── metadata: Metadata +└── entities: list[EntityEmbeddings] + └── EntityEmbeddings + ├── entity: Term # Entity identifier + ├── vector: list[float] # Embedding vector + └── chunk_id: str # Source chunk (provenance) +``` + +### Incorporações de Documentos + +Converte texto em partes diretamente em incorporações vetoriais. + +**Processo:** +1. Receber Parte (Chunk) +2. Chamar o serviço de incorporação com o texto da parte +3. Saída: Incorporações de Documento (DocumentEmbeddings) + +**Esquema: Incorporações de Documento (DocumentEmbeddings)** + +``` +DocumentEmbeddings +├── metadata: Metadata +└── chunks: list[ChunkEmbeddings] + └── ChunkEmbeddings + ├── chunk_id: str # Chunk identifier + └── vector: list[float] # Embedding vector +``` + +### Incorporações de Linhas + +Converte campos de índice de linha em incorporações vetoriais. + +**Processo:** +1. Receber Linhas +2. Incorporar campos de índice configurados +3. Saída para o armazenamento vetorial de linhas + +## Fase 6: Armazenamento + +### Armazenamento Triplo + +Recebe: Triplas +Armazenamento: Cassandra (tabelas centradas em entidades) +Grafos nomeados separam o conhecimento central da procedência: + `""` (padrão): Fatos de conhecimento central + `urn:graph:source`: Procedência de extração + `urn:graph:retrieval`: Explicabilidade em tempo de consulta + +### Armazenamento Vetorial (Incorporações de Grafos) + +Recebe: Incorporações de Grafos +Armazenamento: Qdrant, Milvus ou Pinecone +Indexado por: IRI da entidade +Metadados: chunk_id para procedência + +### Armazenamento Vetorial (Incorporações de Documentos) + +Recebe: Incorporações de Documentos +Armazenamento: Qdrant, Milvus ou Pinecone +Indexado por: chunk_id + +### Armazenamento de Linhas + +Recebe: Linhas +Armazenamento: Cassandra +Estrutura de tabela orientada por esquema + +### Armazenamento Vetorial de Linhas + +Recebe: Incorporações de linhas +Armazenamento: Banco de dados vetorial +Indexado por: campos de índice de linha + +## Análise de Campos de Metadados + +### Campos Ativamente Utilizados + +| Campo | Uso | +|-------|-------| +| `metadata.id` | Identificador de documento/fragmento, registro, procedência | +| `metadata.user` | Multilocação, roteamento de armazenamento | +| `metadata.collection` | Seleção de coleção de destino | +| `document_id` | Referência do bibliotecário, vinculação de procedência | +| `chunk_id` | Rastreamento de procedência através do pipeline | + +<<<<<<< HEAD +### Campos Potencialmente Redundantes + +| Campo | Status | +|-------|--------| +| `metadata.metadata` | Definido como `[]` por todos os extratores; metadados de nível de documento agora gerenciados pelo bibliotecário no momento do envio | +======= +### Campos Removidos + +| Campo | Status | +|-------|--------| +| `metadata.metadata` | Removido da classe `Metadata`. Triplas de metadados de nível de documento agora são emitidas diretamente pelo bibliotecário para o armazenamento de triplas no momento do envio, e não são transmitidas através do pipeline de extração. | +>>>>>>> e3bcbf73 (The metadata field (list of triples) in the pipeline Metadata class) + +### Padrão de Campos de Bytes + +Todos os campos de conteúdo (`data`, `text`, `chunk`) são `bytes`, mas são imediatamente decodificados para strings UTF-8 por todos os processadores. Nenhum processador usa bytes brutos. + +## Configuração do Fluxo + +Os fluxos são definidos externamente e fornecidos ao bibliotecário através do serviço de configuração. Cada fluxo especifica: + +Filas de entrada (`text-load`, `document-load`) +Cadeia de processadores +Parâmetros (tamanho do fragmento, método de extração, etc.) + +Padrões de fluxo de exemplo: +`pdf-graphrag`: PDF → Decodificador → Fragmentador → Definições + Relacionamentos → Incorporações +`text-graphrag`: Texto → Fragmentador → Definições + Relacionamentos → Incorporações +`pdf-ontology`: PDF → Decodificador → Fragmentador → Extração de Ontologia → Incorporações +`text-rows`: Texto → Fragmentador → Extração de Linhas → Armazenamento de Linhas diff --git a/docs/tech-specs/extraction-flows.ru.md b/docs/tech-specs/extraction-flows.ru.md new file mode 100644 index 00000000..81370281 --- /dev/null +++ b/docs/tech-specs/extraction-flows.ru.md @@ -0,0 +1,347 @@ +# Потоки извлечения данных + +Этот документ описывает, как данные передаются через конвейер извлечения данных TrustGraph, начиная с отправки документов и заканчивая хранением в хранилищах знаний. + +## Обзор + +``` +┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐ +│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │ +│ │ │ (PDF only) │ │ │ │ Extraction │ +│ │────────────────────────▶│ │ │ │ +└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘ + │ │ + │ ├──▶ Triples + │ ├──▶ Entity Contexts + │ └──▶ Rows + │ + └──▶ Document Embeddings +``` + +## Хранение контента + +### Blob-хранилище (S3/Minio) + +Содержимое документов хранится в блочном хранилище, совместимом с S3: +Формат пути: `doc/{object_id}`, где object_id - это UUID +Все типы документов хранятся здесь: исходные документы, страницы, фрагменты + +### Хранилище метаданных (Cassandra) + +Метаданные документов, хранящиеся в Cassandra, включают: +Идентификатор документа, заголовок, тип (MIME-тип) +Ссылку `object_id` на блочное хранилище +Ссылку `parent_id` для дочерних документов (страниц, фрагментов) +Тип `document_type`: "source", "page", "chunk", "answer" + +### Порог для встроенных данных и потоковой передачи + +Передача контента использует стратегию, основанную на размере: +**< 2 МБ**: Контент включается непосредственно в сообщение (в кодировке base64) +**≥ 2 МБ**: Отправляется только `document_id`; процессор извлекает данные через API librarian + +## Этап 1: Отправка документа (Librarian) + +### Точка входа + +Документы поступают в систему через операцию `add-document` librarian: +1. Контент загружается в блочное хранилище +2. Создается запись метаданных в Cassandra +3. Возвращается идентификатор документа + +### Запуск извлечения + +Операция `add-processing` запускает извлечение: +Указывает `document_id`, `flow` (идентификатор конвейера), `collection` (целевое хранилище) +Операция `load_document()` librarian извлекает контент и публикует его в очередь ввода конвейера + +### Схема: Document + +``` +Document +├── metadata: Metadata +│ ├── id: str # Document identifier +│ ├── user: str # Tenant/user ID +│ ├── collection: str # Target collection +│ └── metadata: list[Triple] # (largely unused, historical) +├── data: bytes # PDF content (base64, if inline) +└── document_id: str # Librarian reference (if streaming) +``` + +**Маршрутизация**: Основана на поле `kind`: +`application/pdf` → очередь `document-load` → Декодер PDF +`text/plain` → очередь `text-load` → Разделитель (Chunker) + +## Этап 2: Декодер PDF + +Преобразует документы PDF в текстовые страницы. + +### Процесс + +1. Получение содержимого (встроенное `data` или через `document_id` от библиотекаря) +2. Извлечение страниц с использованием PyPDF +3. Для каждой страницы: + Сохранение как дочерний документ в библиотеке (`{doc_id}/p{page_num}`) + Отправка информации о происхождении (страница получена из документа) + Передача разделителю (chunker) + +### Схема: TextDocument + +``` +TextDocument +├── metadata: Metadata +│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1) +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── text: bytes # Page text content (if inline) +└── document_id: str # Librarian reference (e.g., "doc123/p1") +``` + +## Этап 3: Разделение на фрагменты + +Разделяет текст на фрагменты заданного размера. + +### Параметры (настраиваются в процессе выполнения) + +`chunk_size`: Целевой размер фрагмента в символах (по умолчанию: 2000) +`chunk_overlap`: Перекрытие между фрагментами (по умолчанию: 100) + +### Процесс + +1. Получение содержимого текста (встроенного или через библиотеку) +2. Разделение с использованием рекурсивного разделителя символов +3. Для каждого фрагмента: + Сохранение как дочерний документ в библиотеке (`{parent_id}/c{index}`) + Вывод информации о происхождении (фрагмент получен из страницы/документа) + Передача на этапы обработки извлечения + +### Схема: Фрагмент + +``` +Chunk +├── metadata: Metadata +│ ├── id: str # Chunk URI +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── chunk: bytes # Chunk text content +└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3") +``` + +### Иерархия идентификаторов документов + +Дочерние документы кодируют свою родословную в идентификаторе: +Источник: `doc123` +Страница: `doc123/p5` +Часть страницы: `doc123/p5/c2` +Часть текста: `doc123/c2` + +## Этап 4: Извлечение знаний + +Доступно несколько шаблонов извлечения, выбираемых конфигурацией потока. + +### Шаблон A: Базовый GraphRAG + +Два параллельных процессора: + +**kg-extract-definitions** +Вход: Часть текста +Выход: Тройки (определения сущностей), Контексты сущностей +Извлекает: метки сущностей, определения + +**kg-extract-relationships** +Вход: Часть текста +Выход: Тройки (отношения), Контексты сущностей +Извлекает: отношения субъект-предикат-объект + +### Шаблон B: Основанный на онтологии (kg-extract-ontology) + +Вход: Часть текста +Выход: Тройки, Контексты сущностей +Использует настроенную онтологию для управления извлечением + +### Шаблон C: Основанный на агентах (kg-extract-agent) + +Вход: Часть текста +Выход: Тройки, Контексты сущностей +Использует агентную платформу для извлечения + +### Шаблон D: Извлечение строк (kg-extract-rows) + +Вход: Часть текста +Выход: Строки (структурированные данные, а не тройки) +Использует определение схемы для извлечения структурированных записей + +### Схема: Тройки + +``` +Triples +├── metadata: Metadata +│ ├── id: str +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] # (set to [] by extractors) +└── triples: list[Triple] + └── Triple + ├── s: Term # Subject + ├── p: Term # Predicate + ├── o: Term # Object + └── g: str | None # Named graph +``` + +### Схема: EntityContexts + +``` +EntityContexts +├── metadata: Metadata +└── entities: list[EntityContext] + └── EntityContext + ├── entity: Term # Entity identifier (IRI) + ├── context: str # Textual description for embedding + └── chunk_id: str # Source chunk ID (provenance) +``` + +### Схема: Строки + +``` +Rows +├── metadata: Metadata +├── row_schema: RowSchema +│ ├── name: str +│ ├── description: str +│ └── fields: list[Field] +└── rows: list[dict[str, str]] # Extracted records +``` + +## Этап 5: Генерация векторных представлений (эмбеддингов) + +### Векторные представления графа + +Преобразует контексты сущностей в векторные представления. + +**Процесс:** +1. Получение контекстов сущностей (EntityContexts) +2. Вызов сервиса генерации векторных представлений с текстом контекста +3. Вывод векторных представлений графа (отображение сущности во вектор) + +**Схема: Векторные представления графа (GraphEmbeddings)** + +``` +GraphEmbeddings +├── metadata: Metadata +└── entities: list[EntityEmbeddings] + └── EntityEmbeddings + ├── entity: Term # Entity identifier + ├── vector: list[float] # Embedding vector + └── chunk_id: str # Source chunk (provenance) +``` + +### Векторные представления документов + +Преобразует текстовые фрагменты непосредственно в векторные представления. + +**Процесс:** +1. Получение фрагмента текста +2. Вызов сервиса векторизации с текстом фрагмента +3. Вывод векторного представления документа + +**Схема: Векторное представление документа** + +``` +DocumentEmbeddings +├── metadata: Metadata +└── chunks: list[ChunkEmbeddings] + └── ChunkEmbeddings + ├── chunk_id: str # Chunk identifier + └── vector: list[float] # Embedding vector +``` + +### Встраивания строк + +Преобразует поля индекса строк в векторные представления. + +**Процесс:** +1. Получение строк +2. Встраивание настроенных полей индекса +3. Вывод в хранилище векторов строк + +## Этап 6: Хранение + +### Тройной магазин + +Получает: Тройки +Хранение: Cassandra (таблицы, ориентированные на сущности) +Именованные графы разделяют основные знания от информации об источнике: + `""` (по умолчанию): Факты основных знаний + `urn:graph:source`: Информация об источнике извлечения + `urn:graph:retrieval`: Объяснимость во время запроса + +### Хранилище векторов (Встраивания графов) + +Получает: Встраивания графов +Хранение: Qdrant, Milvus или Pinecone +Индексируется по: IRI сущности +Метаданные: chunk_id для информации об источнике + +### Хранилище векторов (Встраивания документов) + +Получает: Встраивания документов +Хранение: Qdrant, Milvus или Pinecone +Индексируется по: chunk_id + +### Хранилище строк + +Получает: Строки +Хранение: Cassandra +Структура таблицы, определяемая схемой + +### Хранилище векторов строк + +Получает: Встраивания строк +Хранение: Векторная база данных +Индексируется по: полям индекса строк + +## Анализ полей метаданных + +### Активно используемые поля + +| Поле | Использование | +|-------|-------| +| `metadata.id` | Идентификатор документа/фрагмента, ведение журнала, информация об источнике | +| `metadata.user` | Многопользовательский режим, маршрутизация хранения | +| `metadata.collection` | Выбор целевой коллекции | +| `document_id` | Ссылка на библиотекаря, связывание с информацией об источнике | +| `chunk_id` | Отслеживание информации об источнике через конвейер | + +<<<<<<< HEAD +### Потенциально избыточные поля + +| Поле | Статус | +|-------|--------| +| `metadata.metadata` | Устанавливается в `[]` всеми извлекателями; метаданные на уровне документа теперь обрабатываются библиотекарем при отправке | +======= +### Удаленные поля + +| Поле | Статус | +|-------|--------| +| `metadata.metadata` | Удалено из класса `Metadata`. Тройки метаданных на уровне документа теперь напрямую выдаются библиотекарем в тройной магазин при отправке, а не передаются через конвейер извлечения. | +>>>>>>> e3bcbf73 (The metadata field (list of triples) in the pipeline Metadata class) + +### Шаблон полей байтов + +Все поля содержимого (`data`, `text`, `chunk`) являются `bytes`, но немедленно декодируются в строки UTF-8 всеми процессорами. Ни один процессор не использует необработанные байты. + +## Конфигурация потока + +Потоки определяются внешне и предоставляются библиотекарию через сервис конфигурации. Каждый поток определяет: + +Входные очереди (`text-load`, `document-load`) +Цепочка процессоров +Параметры (размер фрагмента, метод извлечения и т. д.) + +Пример шаблонов потоков: +`pdf-graphrag`: PDF → Decoder → Chunker → Definitions + Relationships → Embeddings +`text-graphrag`: Text → Chunker → Definitions + Relationships → Embeddings +`pdf-ontology`: PDF → Decoder → Chunker → Ontology Extraction → Embeddings +`text-rows`: Text → Chunker → Row Extraction → Row Store diff --git a/docs/tech-specs/extraction-flows.sw.md b/docs/tech-specs/extraction-flows.sw.md new file mode 100644 index 00000000..2f0a72d8 --- /dev/null +++ b/docs/tech-specs/extraction-flows.sw.md @@ -0,0 +1,347 @@ +# Mchakato wa Utoaji + +Hati hii inaeleza jinsi data inapita katika mfumo wa utoaji wa TrustGraph, kuanzia utoaji wa hati hadi uhifadhi katika hifadhia za maarifa. + +## Muhtasari + +``` +┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐ +│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │ +│ │ │ (PDF only) │ │ │ │ Extraction │ +│ │────────────────────────▶│ │ │ │ +└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘ + │ │ + │ ├──▶ Triples + │ ├──▶ Entity Contexts + │ └──▶ Rows + │ + └──▶ Document Embeddings +``` + +## Hifadhi ya Maudhui + +### Uhifadhi wa Data (S3/Minio) + +Maudhui ya nyaraka huhifadhiwa katika uhifadhi wa data unaolingana na S3: +Muundo wa njia: `doc/{object_id}` ambapo object_id ni UUID +Aina zote za nyaraka huhifadhiwa hapa: nyaraka za asili, kurasa, sehemu + +### Uhifadhi wa MetaData (Cassandra) + +MetaData ya nyaraka iliyohifadhiwa katika Cassandra ni pamoja na: +Kitambulisho cha nyaraka, kichwa, aina (aina ya MIME) +Rejea ya `object_id` kwa uhifadhi wa data +`parent_id` kwa nyaraka za watoto (kurasa, sehemu) +`document_type`: "chanzo", "ukurasa", "sehemu", "jibu" + +### Kigezo cha Kwanza na la Kuendelea + +Usafirishaji wa maudhui hutumia mkakati unaotegemea saizi: +**< 2MB**: Maudhui yajumuishwa ndani ya ujumbe (yamekodishwa kwa base64) +**≥ 2MB**: `document_id` pekee hutumwa; mchakato hupata kupitia API ya msimamizi + +## Hatua ya 1: Uwasilishaji wa Nyaraka (Msimamizi) + +### Kifaa cha Kuanzia + +Nyaraka huingia katika mfumo kupitia operesheni ya `add-document` ya msimamizi: +1. Maudhui yamepakuliwa kwenye uhifadhi wa data +2. Rekodi ya metaData imeundwa katika Cassandra +3. Inarudisha kitambulisho cha nyaraka + +### Kuanzisha Utoaji + +Operesheni ya `add-processing` inaanzisha utoaji: +Inaonyesha `document_id`, `flow` (kitambulisho cha mnyororo), `collection` (hifadhi inayolengwa) +Msimamizi wa `load_document()` hupata maudhui na huyaweka kwenye folyo ya ingizo + +### Muundo: Nyaraka + +``` +Document +├── metadata: Metadata +│ ├── id: str # Document identifier +│ ├── user: str # Tenant/user ID +│ ├── collection: str # Target collection +│ └── metadata: list[Triple] # (largely unused, historical) +├── data: bytes # PDF content (base64, if inline) +└── document_id: str # Librarian reference (if streaming) +``` + +**Uelekezaji:** Kulingana na sehemu `kind`: +`application/pdf` → Kundi `document-load` → Kipangishi cha PDF +`text/plain` → Kundi `text-load` → Kipande + +## Hatua ya 2: Kipangishi cha PDF + +Hubadilisha hati za PDF kuwa kurasa za maandishi. + +### Mchakato + +1. Pata maudhui (moja kwa moja `data` au kupitia `document_id` kutoka kwa msimamizi) +2. Toa kurasa kwa kutumia PyPDF +3. Kwa kila ukurasa: + Hifadhi kama hati ndogo kwa msimamizi (`{doc_id}/p{page_num}`) + Toa matoleo ya asili (ukurasa ulichukuliwa kutoka hati) + Peleka kwa kipande + +### Mpango: TextDocument + +``` +TextDocument +├── metadata: Metadata +│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1) +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── text: bytes # Page text content (if inline) +└── document_id: str # Librarian reference (e.g., "doc123/p1") +``` + +## Hatua ya 3: Kugawanya maandishi + +Hugawanya maandishi katika sehemu ndogo kulingana na ukubwa uliopangwa. + +### Vigezo (vielekezi ambavyo vinaweza kusanidiwa) + +`chunk_size`: Ukubwa unaolengwa wa sehemu ndogo kwa herufi (kiwango chachilia: 2000) +`chunk_overlap`: Mzunguko kati ya sehemu ndogo (kiwango chachilia: 100) + +### Mchakato + +1. Pata maudhui ya maandishi (moja kwa moja au kupitia mfumo wa kumbukumbu) +2. Gawanya kwa kutumia mgawaji wa herufi unaojielekeza +3. Kwa kila sehemu ndogo: + Hifadhi kama hati ndogo katika mfumo wa kumbukumbu (`{parent_id}/c{index}`) + Toa taarifa za asili (sehemu ndogo ilitokana na ukurasa/hati) + Peleka kwa vichakavu vya utoaji + +### Muundo: Sehemu Ndogo + +``` +Chunk +├── metadata: Metadata +│ ├── id: str # Chunk URI +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── chunk: bytes # Chunk text content +└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3") +``` + +### Hierarkia ya Kitambulisho cha Hati + +Hati za chini huandika urithi wao katika kitambulisho: +Chanzo: `doc123` +Ukurasa: `doc123/p5` +Sehemu kutoka ukurasa: `doc123/p5/c2` +Sehemu kutoka maandishi: `doc123/c2` + +## Hatua ya 4: Utokaji wa Maarifa + +Mfumo mbalimbali wa utokaji unapatikana, unaochaguliwa na usanidi wa mtiririko. + +### Mfumo A: Basic GraphRAG + +Wasindikaji wawili sambamba: + +**kg-extract-definitions** +Ingizo: Sehemu +Patoto: Triples (ufafanuzi wa vitu), EntityContexts +Hutokaje: lebo za vitu, ufafanuzi + +**kg-extract-relationships** +Ingizo: Sehemu +Patoto: Triples (uhusiano), EntityContexts +Hutokaje: uhusiano wa subjekti-kivumbe-kijisumu + +### Mfumo B: Inayoendeshwa na Ontolojia (kg-extract-ontology) + +Ingizo: Sehemu +Patoto: Triples, EntityContexts +Hutumia ontolojia iliyosanidiwa ili kuongoza utokaji + +### Mfumo C: Inayoendeshwa na Wakala (kg-extract-agent) + +Ingizo: Sehemu +Patoto: Triples, EntityContexts +Hutumia mfumo wa wakala kwa utokaji + +### Mfumo D: Utokaji wa Mistari (kg-extract-rows) + +Ingizo: Sehemu +Patoto: Mistari (data iliyopangwa, si triples) +Hutumia ufafanuzi wa schema ili kutokaje rekodi zilizopangwa + +### Schema: Triples + +``` +Triples +├── metadata: Metadata +│ ├── id: str +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] # (set to [] by extractors) +└── triples: list[Triple] + └── Triple + ├── s: Term # Subject + ├── p: Term # Predicate + ├── o: Term # Object + └── g: str | None # Named graph +``` + +### Mfumo: EntityContexts + +``` +EntityContexts +├── metadata: Metadata +└── entities: list[EntityContext] + └── EntityContext + ├── entity: Term # Entity identifier (IRI) + ├── context: str # Textual description for embedding + └── chunk_id: str # Source chunk ID (provenance) +``` + +### Mfumo: Safu + +``` +Rows +├── metadata: Metadata +├── row_schema: RowSchema +│ ├── name: str +│ ├── description: str +│ └── fields: list[Field] +└── rows: list[dict[str, str]] # Extracted records +``` + +## Hatua ya 5: Uzalishaji wa Uelekezo (Embeddings) + +### Uelekezo wa Grafu + +Hubadilisha muktadha wa vitu katika uelekezo wa vector. + +**Mchakato:** +1. Pokea Muktadha wa Vitu (EntityContexts) +2. Piga simu kwa huduma ya uelekezo (embeddings) kwa kutumia maandishi ya muktadha +3. Toa Uelekezo wa Grafu (ramani ya kitu hadi vector) + +**Muundo: Uelekezo wa Grafu (GraphEmbeddings)** + +``` +GraphEmbeddings +├── metadata: Metadata +└── entities: list[EntityEmbeddings] + └── EntityEmbeddings + ├── entity: Term # Entity identifier + ├── vector: list[float] # Embedding vector + └── chunk_id: str # Source chunk (provenance) +``` + +### Uelekezaji wa Hati + +Hubadilisha maandishi ya sehemu moja moja kwa uelekezaji wa vector. + +**Mchakato:** +1. Pokea Sehemu +2. Piga simu kwa huduma ya uelekezaji kwa kutumia maandishi ya sehemu +3. Toa Uelekezaji wa Hati + +**Muundo: Uelekezaji wa Hati** + +``` +DocumentEmbeddings +├── metadata: Metadata +└── chunks: list[ChunkEmbeddings] + └── ChunkEmbeddings + ├── chunk_id: str # Chunk identifier + └── vector: list[float] # Embedding vector +``` + +### Ulinganisho wa Safu + +Hubadilisha nambari za safu kuwa ulinganisho wa vekta. + +**Mchakato:** +1. Pokea Safu +2. Linganisha nambari zilizoelezwa za safu +3. Toa kwenye hifadhi ya vekta ya safu + +## Hatua ya 6: Uhifadhi + +### Hifadhi ya Triple + +Inapokea: Triples +Uhifadhi: Cassandra (meza zenye msingi wa vitu) +Picha zilizoainishwa zinatenganisha maarifa ya msingi kutoka kwa asili: + `""` (ya kawaida): Ukweli wa maarifa ya msingi + `urn:graph:source`: Asili ya uondoaji + `urn:graph:retrieval`: Uwezekano wa kufafanua wakati wa kuuliza + +### Hifadhi ya Vektaja (Ulinganisho wa Picha) + +Inapokea: Ulinganisho wa Picha +Uhifadhi: Qdrant, Milvus, au Pinecone +Imeorodheshwa kwa: IRI ya kitu +Meta: chunk_id kwa asili + +### Hifadhi ya Vektaja (Ulinganisho wa Nyaraka) + +Inapokea: Ulinganisho wa Nyaraka +Uhifadhi: Qdrant, Milvus, au Pinecone +Imeorodheshwa kwa: chunk_id + +### Hifadhi ya Safu + +Inapokea: Safu +Uhifadhi: Cassandra +Muundo wa meza unaoongozwa na schema + +### Hifadhi ya Vektaja ya Safu + +Inapokea: Ulinganisho wa safu +Uhifadhi: Hifadhi ya Vektaja +Imeorodheshwa kwa: nambari za safu + +## Uchunguzi wa Uwanja wa Meta + +### Uwanja Unaotumika Kwa Kazi + +| Uwanja | Matumizi | +|-------|-------| +| `metadata.id` | Kitambulisho cha nyaraka/kipande, uandishi wa matukio, asili | +| `metadata.user` | Usimamizi wa wateja wengi, uelekezaji wa uhifadhi | +| `metadata.collection` | Uchaguzi wa mkusanyiko unaolengwa | +| `document_id` | Rejea ya mkusanyaji, kuunganisha asili | +| `chunk_id` | Kufuatilia asili kupitia mnyororo | + +<<<<<<< HEAD +### Uwanja Unaowezekana kuwa Ziada + +| Uwanja | Hali | +|-------|--------| +| `metadata.metadata` | Imepangwa kama `[]` na vichujio vyote; meta ya kiwango cha nyaraka sasa inashughulikiwa na mkusanyaji wakati wa kuwasilisha | +======= +### Uwanja Ulioondolewa + +| Uwanja | Hali | +|-------|--------| +| `metadata.metadata` | Imeondolewa kutoka kwa darasa la `Metadata`. Triples za meta ya kiwango cha nyaraka sasa hutolewa moja kwa moja na mkusanyaji kwenye hifadhi ya triples wakati wa kuwasilisha, sio kuletwa kupitia mnyororo wa uondoaji. | +>>>>>>> e3bcbf73 (Uwanja wa meta (orodha ya triples) katika darasa la Mnyororo wa Meta) + +### Mfumo wa Uwanja wa Bytes + +Uwanja wote wa yaliyomo (`data`, `text`, `chunk`) ni `bytes` lakini huondolewa mara moja kuwa maandishi ya UTF-8 na vichujio vyote. Hakuna kichujio kinachotumia bytes mbichi. + +## Usanidi wa Mnyororo + +Mnyororo huainishwa nje na hutolewa kwa mkusanyaji kupitia huduma ya usanidi. Kila mnyororo unaonyesha: + +Ndege za ingizo (`text-load`, `document-load`) +Mnyororo wa vichujio +Vigezo (ukubwa wa kipande, njia ya uondoaji, n.k.) + +Mifano ya mnyororo: +`pdf-graphrag`: PDF → Dekoda → Kipande → Maelezo + Mahusiano → Ulinganisho +`text-graphrag`: Nakshata → Kipande → Maelezo + Mahusiano → Ulinganisho +`pdf-ontology`: PDF → Dekoda → Kipande → Uondoaji wa Ontolojia → Ulinganisho +`text-rows`: Nakshata → Kipande → Uondoaji wa Safu → Hifadhi ya Safu diff --git a/docs/tech-specs/extraction-flows.tr.md b/docs/tech-specs/extraction-flows.tr.md new file mode 100644 index 00000000..65d5c8d8 --- /dev/null +++ b/docs/tech-specs/extraction-flows.tr.md @@ -0,0 +1,347 @@ +# Veri Çıkarma Akışları + +Bu belge, verilerin TrustGraph veri çıkarma işlem hattı üzerinden nasıl aktığını, belge gönderiminden başlayarak bilgi depolarına kaydedilmesine kadar olan süreci açıklamaktadır. + +## Genel Bakış + +``` +┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐ +│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │ +│ │ │ (PDF only) │ │ │ │ Extraction │ +│ │────────────────────────▶│ │ │ │ +└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘ + │ │ + │ ├──▶ Triples + │ ├──▶ Entity Contexts + │ └──▶ Rows + │ + └──▶ Document Embeddings +``` + +## İçerik Depolama + +### Blob Depolama (S3/Minio) + +Belge içeriği, S3 uyumlu blob depolama alanında saklanır: +Yol formatı: `doc/{object_id}`, burada object_id bir UUID'dir. +Tüm belge türleri burada saklanır: kaynak belgeler, sayfalar, parçalar. + +### Metaveri Depolama (Cassandra) + +Cassandra'da saklanan belge metaverileri şunları içerir: +Belge ID'si, başlık, tür (MIME türü). +Blob depolama alanına `object_id` referansı. +Alt belgelere (sayfalar, parçalar) ait `parent_id`. +`document_type`: "kaynak", "sayfa", "parça", "cevap". + +### İçerik vs. Akış Eşiği + +İçerik iletimi, boyuta dayalı bir strateji kullanır: +**< 2MB**: İçerik, mesaj içinde (base64 ile kodlanmış) yer alır. +**≥ 2MB**: Yalnızca `document_id` gönderilir; işlemci, kütüphaneci API'si aracılığıyla içeriği alır. + +## 1. Aşama: Belge Gönderimi (Kütüphaneci) + +### Giriş Noktası + +Belgeler, kütüphanecinin `add-document` işlemi aracılığıyla sisteme girer: +1. İçerik, blob depolama alanına yüklenir. +2. Cassandra'da bir metaveri kaydı oluşturulur. +3. Belge ID'si döndürülür. + +### Çıkarım Tetikleme + +`add-processing` işlemi, çıkarımı tetikler: +`document_id`, `flow` (işlem hattı ID'si) ve `collection` (hedef depolama alanı) belirtir. +Kütüphanecinin `load_document()` işlemi, içeriği alır ve akış giriş kuyruğuna yayınlar. + +### Şema: Belge + +``` +Document +├── metadata: Metadata +│ ├── id: str # Document identifier +│ ├── user: str # Tenant/user ID +│ ├── collection: str # Target collection +│ └── metadata: list[Triple] # (largely unused, historical) +├── data: bytes # PDF content (base64, if inline) +└── document_id: str # Librarian reference (if streaming) +``` + +**Yönlendirme**: `kind` alanına göre: +`application/pdf` → `document-load` kuyruğu → PDF Kod Çözücü +`text/plain` → `text-load` kuyruğu → Parçalayıcı + +## 2. Aşama: PDF Kod Çözücü + +PDF belgelerini metin sayfalarına dönüştürür. + +### İşlem + +1. İçeriği al (doğrudan `data` veya `document_id` üzerinden kütüphaneciden) +2. Sayfaları PyPDF kullanarak çıkar +3. Her sayfa için: + Kütüphanecide alt belge olarak kaydet (`{doc_id}/p{page_num}`) + Kaynak üçlülerini yayınla (sayfa, belgeden türetilmiştir) + Parçalayıcıya ilet + +### Şema: TextDocument + +``` +TextDocument +├── metadata: Metadata +│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1) +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── text: bytes # Page text content (if inline) +└── document_id: str # Librarian reference (e.g., "doc123/p1") +``` + +## 3. Aşama: Parçalayıcı (Chunker) + +Metni, yapılandırılmış boyutta parçalara ayırır. + +### Parametreler (akışa bağımlı olarak yapılandırılabilir) + +`chunk_size`: Karakter cinsinden hedef parça boyutu (varsayılan: 2000) +`chunk_overlap`: Parçalar arasındaki örtüşme (varsayılan: 100) + +### İşlem + +1. Metin içeriğini alın (doğrudan veya kütüphaneci aracılığıyla) +2. Özyinelemeli karakter ayırıcı kullanarak parçalara ayırın +3. Her parça için: + Kütüphanecide alt belge olarak kaydedin (`{parent_id}/c{index}`) + Kaynak bilgilerini yayınlayın (parça, sayfadan/belgeden türetilmiştir) + Çıkarma işleme modüllerine yönlendirin + +### Şema: Parça (Chunk) + +``` +Chunk +├── metadata: Metadata +│ ├── id: str # Chunk URI +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── chunk: bytes # Chunk text content +└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3") +``` + +### Belge Kimlik Hiyerarşisi + +Alt belgeler, kimlik içinde kendi kökenlerini kodlar: +Kaynak: `doc123` +Sayfa: `doc123/p5` +Sayfadan parça: `doc123/p5/c2` +Metinden parça: `doc123/c2` + +## 4. Aşama: Bilgi Çıkarımı + +Kullanılabilir çoklu çıkarma kalıpları, akış yapılandırması tarafından seçilir. + +### Kalıp A: Temel GraphRAG + +İki paralel işlemci: + +**kg-extract-definitions** +Giriş: Parça +Çıkış: Üçlüler (varlık tanımları), Varlık Bağlamları +Çıkarır: varlık etiketleri, tanımlar + +**kg-extract-relationships** +Giriş: Parça +Çıkış: Üçlüler (ilişkiler), Varlık Bağlamları +Çıkarır: özne-yüklem-nesne ilişkileri + +### Kalıp B: Ontoloji Odaklı (kg-extract-ontology) + +Giriş: Parça +Çıkış: Üçlüler, Varlık Bağlamları +Çıkarımı yönlendirmek için yapılandırılmış bir ontoloji kullanır + +### Kalıp C: Ajan Tabanlı (kg-extract-agent) + +Giriş: Parça +Çıkış: Üçlüler, Varlık Bağlamları +Çıkarım için ajan çerçevesini kullanır + +### Kalıp D: Satır Çıkarımı (kg-extract-rows) + +Giriş: Parça +Çıkış: Satırlar (üçlüler değil, yapılandırılmış veri) +Yapılandırılmış kayıtları çıkarmak için şema tanımını kullanır + +### Şema: Üçlüler + +``` +Triples +├── metadata: Metadata +│ ├── id: str +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] # (set to [] by extractors) +└── triples: list[Triple] + └── Triple + ├── s: Term # Subject + ├── p: Term # Predicate + ├── o: Term # Object + └── g: str | None # Named graph +``` + +### Şema: Varlık Bağlamları + +``` +EntityContexts +├── metadata: Metadata +└── entities: list[EntityContext] + └── EntityContext + ├── entity: Term # Entity identifier (IRI) + ├── context: str # Textual description for embedding + └── chunk_id: str # Source chunk ID (provenance) +``` + +### Şema: Satırlar + +``` +Rows +├── metadata: Metadata +├── row_schema: RowSchema +│ ├── name: str +│ ├── description: str +│ └── fields: list[Field] +└── rows: list[dict[str, str]] # Extracted records +``` + +## 5. Aşama: Gömme (Embedding) Oluşturma + +### Grafik Gömme (Graph Embeddings) + +Varlık bağlamlarını vektör gömmelerine dönüştürür. + +**Süreç:** +1. Varlık Bağlamlarını Alın +2. Bağlam metniyle gömme hizmetini çağırın +3. GrafikGömme'leri Çıktılayın (varlık → vektör eşlemesi) + +**Şema: GrafikGömme (GraphEmbeddings)** + +``` +GraphEmbeddings +├── metadata: Metadata +└── entities: list[EntityEmbeddings] + └── EntityEmbeddings + ├── entity: Term # Entity identifier + ├── vector: list[float] # Embedding vector + └── chunk_id: str # Source chunk (provenance) +``` + +### Belge Gömme (Document Embeddings) + +Parça metnini doğrudan vektör gömmelerine dönüştürür. + +**Süreç:** +1. Parçayı Al +2. Parça metniyle gömme hizmetini çağır +3. DocumentEmbeddings çıktısını ver + +**Şema: DocumentEmbeddings** + +``` +DocumentEmbeddings +├── metadata: Metadata +└── chunks: list[ChunkEmbeddings] + └── ChunkEmbeddings + ├── chunk_id: str # Chunk identifier + └── vector: list[float] # Embedding vector +``` + +### Satır Gömme (Row Embeddings) + +Satır indeks alanlarını vektör gömmelerine dönüştürür. + +**İşlem:** +1. Satırları Al +2. Yapılandırılmış indeks alanlarını göm +3. Satır vektör deposuna çıktı ver + +## 6. Aşama: Depolama + +### Üçlü Depo (Triple Store) + +Gelen: Üçlüler +Depolama: Cassandra (varlık odaklı tablolar) +İsimlendirilmiş grafikler, temel bilgiyi köken bilgisinden ayırır: + `""` (varsayılan): Temel bilgi gerçekleri + `urn:graph:source`: Çıkarma kökeni + `urn:graph:retrieval`: Sorgu zamanı açıklanabilirliği + +### Vektör Deposu (Grafik Gömme) + +Gelen: GrafikGömme (GraphEmbeddings) +Depolama: Qdrant, Milvus veya Pinecone +Dizin: Varlık IRI'si ile +Metaveri: Köken için chunk_id + +### Vektör Deposu (Belge Gömme) + +Gelen: BelgeGömme (DocumentEmbeddings) +Depolama: Qdrant, Milvus veya Pinecone +Dizin: chunk_id ile + +### Satır Deposu (Row Store) + +Gelen: Satırlar +Depolama: Cassandra +Şema odaklı tablo yapısı + +### Satır Vektör Deposu + +Gelen: Satır gömmeleri +Depolama: Vektör Veritabanı +Dizin: Satır indeks alanları ile + +## Metaveri Alanı Analizi + +### Aktif Olarak Kullanılan Alanlar + +| Alan | Kullanım | +|-------|-------| +| `metadata.id` | Belge/parça tanımlayıcı, günlükleme, köken | +| `metadata.user` | Çoklu kiracılık, depolama yönlendirme | +| `metadata.collection` | Hedef koleksiyon seçimi | +| `document_id` | Kütüphaneci referansı, köken bağlantısı | +| `chunk_id` | İşlem hattı boyunca köken takibi | + +<<<<<<< HEAD +### Potansiyel Olarak Gereksiz Alanlar + +| Alan | Durum | +|-------|--------| +| `metadata.metadata` | Tüm çıkarıcılar tarafından `[]` olarak ayarlanır; belge düzeyindeki metaveri artık gönderim zamanında kütüphaneci tarafından işlenir | +======= +### Kaldırılan Alanlar + +| Alan | Durum | +|-------|--------| +| `metadata.metadata` | `Metadata` sınıfından kaldırıldı. Belge düzeyindeki metaveri üçlüleri artık kütüphaneci tarafından doğrudan üçlü depoya gönderim zamanında gönderilir, çıkarma hattı üzerinden taşınmaz. | +>>>>>>> e3bcbf73 (The metadata field (list of triples) in the pipeline Metadata class) + +### Bayt Alanı Modeli + +Tüm içerik alanları (`data`, `text`, `chunk`) `bytes`'tür, ancak tüm işlemciler tarafından hemen UTF-8 dizelerine kod çözülür. İşlemci tarafından ham bayt kullanılmaz. + +## Akış Yapılandırması + +Akışlar harici olarak tanımlanır ve kütüphaneci aracılığıyla yapılandırma hizmetinden sağlanır. Her akış şunları belirtir: + +Giriş kuyrukları (`text-load`, `document-load`) +İşlemci zinciri +Parametreler (parça boyutu, çıkarma yöntemi, vb.) + +Örnek akış modelleri: +`pdf-graphrag`: PDF → Kod Çözücü → Parçalayıcı → Tanımlar + İlişkiler → Gömme +`text-graphrag`: Metin → Parçalayıcı → Tanımlar + İlişkiler → Gömme +`pdf-ontology`: PDF → Kod Çözücü → Parçalayıcı → Ontoloji Çıkarma → Gömme +`text-rows`: Metin → Parçalayıcı → Satır Çıkarma → Satır Deposu diff --git a/docs/tech-specs/extraction-flows.zh-cn.md b/docs/tech-specs/extraction-flows.zh-cn.md new file mode 100644 index 00000000..20bbc560 --- /dev/null +++ b/docs/tech-specs/extraction-flows.zh-cn.md @@ -0,0 +1,347 @@ +# 数据提取流程 + +本文档描述了数据如何通过 TrustGraph 提取流程进行流动,从文档提交到存储在知识库中。 + +## 概述 + +``` +┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐ +│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │ +│ │ │ (PDF only) │ │ │ │ Extraction │ +│ │────────────────────────▶│ │ │ │ +└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘ + │ │ + │ ├──▶ Triples + │ ├──▶ Entity Contexts + │ └──▶ Rows + │ + └──▶ Document Embeddings +``` + +## 内容存储 + +### 对象存储 (S3/Minio) + +文档内容存储在兼容 S3 的对象存储中: +路径格式:`doc/{object_id}`,其中 object_id 是一个 UUID +所有文档类型都存储在此处:源文档、页面、分块 + +### 元数据存储 (Cassandra) + +文档元数据存储在 Cassandra 中,包括: +文档 ID、标题、类型 (MIME 类型) +`object_id` 引用对象存储 +`parent_id` 用于子文档 (页面、分块) +`document_type`: "source", "page", "chunk", "answer" + +### 内联与流式传输阈值 + +内容传输使用基于大小的策略: +**< 2MB**: 内容以内联方式包含在消息中 (base64 编码) +**≥ 2MB**: 仅发送 `document_id`;处理器通过 librarian API 获取 + +## 阶段 1:文档提交 (Librarian) + +### 入口点 + +文档通过 librarian 的 `add-document` 操作进入系统: +1. 内容上传到对象存储 +2. 在 Cassandra 中创建元数据记录 +3. 返回文档 ID + +### 触发提取 + +`add-processing` 操作触发提取: +指定 `document_id`、`flow` (pipeline ID)、`collection` (目标存储) +Librarian 的 `load_document()` 获取内容并发布到 flow 输入队列 + +### 模式:Document + +``` +Document +├── metadata: Metadata +│ ├── id: str # Document identifier +│ ├── user: str # Tenant/user ID +│ ├── collection: str # Target collection +│ └── metadata: list[Triple] # (largely unused, historical) +├── data: bytes # PDF content (base64, if inline) +└── document_id: str # Librarian reference (if streaming) +``` + +**路由 (Routing)**: 基于 `kind` 字段: +`application/pdf` → `document-load` 队列 → PDF 解码器 +`text/plain` → `text-load` 队列 → 分块器 + +## 第二阶段:PDF 解码器 + +将 PDF 文档转换为文本页面。 + +### 流程 + +1. 获取内容(内联 `data` 或通过 `document_id` 从管理员处获取) +2. 使用 PyPDF 提取页面 +3. 对于每个页面: + 另存为管理员中的子文档(`{doc_id}/p{page_num}`) + 发出来源三元组(页面源自文档) + 转发到分块器 + +### 模式:TextDocument + +``` +TextDocument +├── metadata: Metadata +│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1) +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── text: bytes # Page text content (if inline) +└── document_id: str # Librarian reference (e.g., "doc123/p1") +``` + +## 第三阶段:分块器 + +将文本分割成配置大小的块。 + +### 参数(可配置) + +`chunk_size`:目标块大小(以字符为单位)(默认:2000) +`chunk_overlap`:块之间的重叠量(默认:100) + +### 流程 + +1. 获取文本内容(内联或通过 librarian) +2. 使用递归字符分割器进行分割 +3. 对于每个块: + 另存为 librarian 中的子文档(`{parent_id}/c{index}`) + 发出来源三元组(块源自页面/文档) + 转发到提取处理器 + +### 模式:Chunk + +``` +Chunk +├── metadata: Metadata +│ ├── id: str # Chunk URI +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] +├── chunk: bytes # Chunk text content +└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3") +``` + +### 文档ID层级结构 + +子文档在其ID中编码了其来源信息: +来源:`doc123` +页面:`doc123/p5` +页面中的块:`doc123/p5/c2` +文本中的块:`doc123/c2` + +## 第4阶段:知识提取 + +可用多种提取模式,由流程配置选择。 + +### 模式A:基本GraphRAG + +两个并行处理器: + +**kg-extract-definitions** +输入:块 +输出:三元组(实体定义),实体上下文 +提取内容:实体标签,定义 + +**kg-extract-relationships** +输入:块 +输出:三元组(关系),实体上下文 +提取内容:主语-谓语-宾语关系 + +### 模式B:基于本体论的 (kg-extract-ontology) + +输入:块 +输出:三元组,实体上下文 +使用配置的本体论来指导提取 + +### 模式C:基于代理的 (kg-extract-agent) + +输入:块 +输出:三元组,实体上下文 +使用代理框架进行提取 + +### 模式D:行提取 (kg-extract-rows) + +输入:块 +输出:行(结构化数据,不是三元组) +使用模式定义来提取结构化记录 + +### 模式:三元组 + +``` +Triples +├── metadata: Metadata +│ ├── id: str +│ ├── user: str +│ ├── collection: str +│ └── metadata: list[Triple] # (set to [] by extractors) +└── triples: list[Triple] + └── Triple + ├── s: Term # Subject + ├── p: Term # Predicate + ├── o: Term # Object + └── g: str | None # Named graph +``` + +### Schema: EntityContexts + +``` +EntityContexts +├── metadata: Metadata +└── entities: list[EntityContext] + └── EntityContext + ├── entity: Term # Entity identifier (IRI) + ├── context: str # Textual description for embedding + └── chunk_id: str # Source chunk ID (provenance) +``` + +### Schema: Rows + +``` +Rows +├── metadata: Metadata +├── row_schema: RowSchema +│ ├── name: str +│ ├── description: str +│ └── fields: list[Field] +└── rows: list[dict[str, str]] # Extracted records +``` + +## 第 5 阶段:嵌入式表示生成 + +### 图嵌入 + +将实体上下文转换为向量嵌入。 + +**流程:** +1. 接收 EntityContexts (实体上下文) +2. 使用上下文文本调用嵌入服务 +3. 输出 GraphEmbeddings (实体 → 向量映射) + +**模式:GraphEmbeddings** + +``` +GraphEmbeddings +├── metadata: Metadata +└── entities: list[EntityEmbeddings] + └── EntityEmbeddings + ├── entity: Term # Entity identifier + ├── vector: list[float] # Embedding vector + └── chunk_id: str # Source chunk (provenance) +``` + +### 文档嵌入 + +将文本块直接转换为向量嵌入。 + +**流程:** +1. 接收文本块 +2. 使用文本块调用嵌入服务 +3. 输出文档嵌入 + +**模式:文档嵌入** + +``` +DocumentEmbeddings +├── metadata: Metadata +└── chunks: list[ChunkEmbeddings] + └── ChunkEmbeddings + ├── chunk_id: str # Chunk identifier + └── vector: list[float] # Embedding vector +``` + +### 行嵌入 (Row Embeddings) + +将行索引字段转换为向量嵌入。 + +**流程:** +1. 接收行 (Receive Rows) +2. 嵌入配置的索引字段 (Embed configured index fields) +3. 输出到行向量存储 (Output to row vector store) + +## 第 6 阶段:存储 (Stage 6: Storage) + +### 三元组存储 (Triple Store) + +接收:三元组 (Receives: Triples) +存储:Cassandra (以实体为中心的表) (Storage: Cassandra (entity-centric tables)) +命名图将核心知识与来源信息分开: (Named graphs separate core knowledge from provenance:) + `""` (默认): 核心知识事实 (default): Core knowledge facts + `urn:graph:source`: 提取来源 (Extraction provenance) + `urn:graph:retrieval`: 查询时的可解释性 (Query-time explainability) + +### 向量存储 (图嵌入) (Vector Store (Graph Embeddings)) + +接收:图嵌入 (Receives: GraphEmbeddings) +存储:Qdrant、Milvus 或 Pinecone (Storage: Qdrant, Milvus, or Pinecone) +索引:实体 IRI (Indexed by: entity IRI) +元数据:用于来源信息的 chunk_id (Metadata: chunk_id for provenance) + +### 向量存储 (文档嵌入) (Vector Store (Document Embeddings)) + +接收:文档嵌入 (Receives: DocumentEmbeddings) +存储:Qdrant、Milvus 或 Pinecone (Storage: Qdrant, Milvus, or Pinecone) +索引:chunk_id (Indexed by: chunk_id) + +### 行存储 (Row Store) + +接收:行 (Receives: Rows) +存储:Cassandra (Storage: Cassandra) +基于模式的表结构 (Schema-driven table structure) + +### 行向量存储 (Row Vector Store) + +接收:行嵌入 +存储:向量数据库 +索引依据:行索引字段 + +## 元数据字段分析 + +### 正在使用的字段 + +| 字段 | 用途 | +|-------|-------| +| `metadata.id` | 文档/块标识符,日志记录,来源 | +| `metadata.user` | 多租户,存储路由 | +| `metadata.collection` | 目标集合选择 | +| `document_id` | 馆员引用,来源链接 | +| `chunk_id` | 通过流水线进行来源跟踪 | + +<<<<<<< HEAD +### 潜在的冗余字段 + +| 字段 | 状态 | +|-------|--------| +| `metadata.metadata` | 由所有提取器设置为 `[]`;文档级别的元数据现在由馆员在提交时处理 | +======= +### 已移除的字段 + +| 字段 | 状态 | +|-------|--------| +| `metadata.metadata` | 从 `Metadata` 类中移除。文档级别的元数据三元组现在由馆员直接发送到三元存储,而不是通过提取流水线。 | +>>>>>>> e3bcbf73 (The metadata field (list of triples) in the pipeline Metadata class) + +### 字节字段模式 + +所有内容字段(`data`,`text`,`chunk`)都是 `bytes`,但立即被所有处理器解码为 UTF-8 字符串。没有处理器使用原始字节。 + +## 流配置 + +流在外部定义,并通过配置服务提供给馆员。每个流都指定: + +输入队列(`text-load`,`document-load`) +处理器链 +参数(块大小,提取方法等) + +示例流模式: +`pdf-graphrag`:PDF → 解码器 → 分块器 → 定义 + 关系 → 嵌入 +`text-graphrag`:文本 → 分块器 → 定义 + 关系 → 嵌入 +`pdf-ontology`:PDF → 解码器 → 分块器 → 本体提取 → 嵌入 +`text-rows`:文本 → 分块器 → 行提取 → 行存储 diff --git a/docs/tech-specs/extraction-provenance-subgraph.es.md b/docs/tech-specs/extraction-provenance-subgraph.es.md new file mode 100644 index 00000000..2f26dd69 --- /dev/null +++ b/docs/tech-specs/extraction-provenance-subgraph.es.md @@ -0,0 +1,205 @@ +# Origen de la extracción: Modelo de subgrafo + +## Problema + +Actualmente, la generación de la procedencia en tiempo de extracción crea una reificación completa por cada +triple extraído: un `stmt_uri`, `activity_uri` y metadatos PROV-O asociados para cada hecho de conocimiento. El procesamiento de un bloque +que produce 20 relaciones genera aproximadamente 220 triples de procedencia además de los aproximadamente 20 triples de conocimiento, lo que supone una sobrecarga de aproximadamente 10:1. + +Esto es costoso (almacenamiento, indexación, transmisión) y semánticamente +inexacto. Cada bloque se procesa mediante una única llamada a un LLM que produce +todos sus triples en una sola transacción. El modelo actual, que es por triple, +oscurece esto al crear la ilusión de 20 eventos de extracción independientes. + + +Además, dos de los cuatro procesadores de extracción (kg-extract-ontology, +kg-extract-agent) no tienen ninguna procedencia, lo que deja lagunas en el +registro de auditoría. + + +## Solución + + +Reemplazar la reificación por triple con un **modelo de subgrafo**: un único +registro de procedencia por extracción de bloque, compartido entre todos los triples producidos a partir de ese +bloque. + +### Cambio de terminología + +| Antiguo | Nuevo | +|-----|-----| +| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | +| `statement_uri()` | `subgraph_uri()` | +| `tg:reifies` (1:1, identidad) | `tg:contains` (1:muchos, contención) | + +### Estructura objetivo + +Todos los triples de procedencia se almacenan en el grafo con nombre `urn:graph:source`. + +``` +# Subgraph contains each extracted triple (RDF-star quoted triples) + tg:contains <> . + tg:contains <> . + tg:contains <> . + +# Derivation from source chunk + prov:wasDerivedFrom . + prov:wasGeneratedBy . + +# Activity: one per chunk extraction + rdf:type prov:Activity . + rdfs:label "{component_name} extraction" . + prov:used . + prov:wasAssociatedWith . + prov:startedAtTime "2026-03-13T10:00:00Z" . + tg:componentVersion "0.25.0" . + tg:llmModel "gpt-4" . # if available + tg:ontology . # if available + +# Agent: stable per component + rdf:type prov:Agent . + rdfs:label "{component_name}" . +``` + +### Comparación de volúmenes + +Para un bloque que produce N triples extraídos: + +| | Viejo (por triple) | Nuevo (subgrafo) | +|---|---|---| +| `tg:contains` / `tg:reifies` | N | N | +| Triples de actividad | ~9 x N | ~9 | +| Triples de agente | 2 x N | 2 | +| Metadatos de declaración/subgrafo | 2 x N | 2 | +| **Total de triples de procedencia** | **~13N** | **N + 13** | +| **Ejemplo (N=20)** | **~260** | **33** | + +## Alcance + +### Procesadores a Actualizar (procedencia existente, por triple) + +**kg-extract-definitions** +(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) + +Actualmente llama a `statement_uri()` + `triple_provenance_triples()` dentro +del bucle por definición. + +Cambios: +Mover la creación de `subgraph_uri()` y `activity_uri()` antes del bucle +Recolectar los triples `tg:contains` dentro del bucle +Emitir el bloque compartido de actividad/agente una vez después del bucle + +**kg-extract-relationships** +(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`) + +Mismo patrón que definiciones. Mismos cambios. + +### Procesadores a Agregar Procedencia (actualmente ausente) + +**kg-extract-ontology** +(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) + +Actualmente emite triples sin procedencia. Agregar procedencia de subgrafo +utilizando el mismo patrón: un subgrafo por bloque, `tg:contains` para cada +triple extraído. + +**kg-extract-agent** +(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) + +Actualmente emite triples sin procedencia. Agregar procedencia de subgrafo +utilizando el mismo patrón. + +### Cambios en la Biblioteca Compartida de Procedencia + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +Reemplazar `triple_provenance_triples()` con `subgraph_provenance_triples()` +Nueva función acepta una lista de triples extraídos en lugar de uno solo +Genera un `tg:contains` por triple, bloque compartido de actividad/agente +Eliminar el `triple_provenance_triples()` antiguo + +**`trustgraph-base/trustgraph/provenance/uris.py`** + +Reemplazar `statement_uri()` con `subgraph_uri()` + +**`trustgraph-base/trustgraph/provenance/namespaces.py`** + +Reemplazar `TG_REIFIES` con `TG_CONTAINS` + +### No Incluido en el Alcance + +**kg-extract-topics**: procesador de estilo antiguo, no se utiliza actualmente en + flujos estándar +**kg-extract-rows**: produce filas no triples, modelo de procedencia + diferente +**Procedencia en tiempo de consulta** (`urn:graph:retrieval`): preocupación separada, + ya utiliza un patrón diferente (pregunta/exploración/énfasis/síntesis) +**Procedencia de documento/página/bloque** (decodificador de PDF, segmentador): ya utiliza + `derived_entity_triples()` que es por entidad, no por triple — no hay + problema de redundancia + +## Notas de Implementación + +### Reestructuración del Bucle del Procesador + +Antes (por triple, en relaciones): +```python +for rel in rels: + # ... build relationship_triple ... + stmt_uri = statement_uri() + prov_triples = triple_provenance_triples( + stmt_uri=stmt_uri, + extracted_triple=relationship_triple, + ... + ) + triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +Después (subgrafo): +```python +sg_uri = subgraph_uri() + +for rel in rels: + # ... build relationship_triple ... + extracted_triples.append(relationship_triple) + +prov_triples = subgraph_provenance_triples( + subgraph_uri=sg_uri, + extracted_triples=extracted_triples, + chunk_uri=chunk_uri, + component_name=default_ident, + component_version=COMPONENT_VERSION, + llm_model=llm_model, + ontology_uri=ontology_uri, +) +triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) +``` + +### Nueva Firma de Asistente + +```python +def subgraph_provenance_triples( + subgraph_uri: str, + extracted_triples: List[Triple], + chunk_uri: str, + component_name: str, + component_version: str, + llm_model: Optional[str] = None, + ontology_uri: Optional[str] = None, + timestamp: Optional[str] = None, +) -> List[Triple]: + """ + Build provenance triples for a subgraph of extracted knowledge. + + Creates: + - tg:contains link for each extracted triple (RDF-star quoted) + - One prov:wasDerivedFrom link to source chunk + - One activity with agent metadata + """ +``` + +### Cambio importante + +Este es un cambio importante en el modelo de trazabilidad. La trazabilidad no +se ha publicado, por lo que no se necesita ninguna migración. El código antiguo `tg:reifies` / +`statement_uri` se puede eliminar por completo. diff --git a/docs/tech-specs/graph-contexts.ar.md b/docs/tech-specs/graph-contexts.ar.md new file mode 100644 index 00000000..1187949c --- /dev/null +++ b/docs/tech-specs/graph-contexts.ar.md @@ -0,0 +1,336 @@ +# مواصفات تقنية لسياق الرسم البياني + +## نظرة عامة + +تصف هذه المواصفات التغييرات التي تم إجراؤها على المكونات الأساسية للرسم البياني في TrustGraph لمواءمتها مع RDF 1.2 ولتقديم دعم كامل لسمات مجموعة بيانات RDF. هذا تغيير جذري لإصدار 2.x. + +### إصدارات + +- **2.0**: إصدار للمستخدمين الأوائل. تتوفر الميزات الأساسية، وقد لا تكون جاهزة تمامًا للإنتاج. +- **2.1 / 2.2**: إصدار جاهز للإنتاج. الاستقرار والشمولية تم التحقق منهما. + +إن توفير مرونة بشأن مستوى النضج هو مقصود - يمكن للمستخدمين الأوائل الوصول إلى إمكانيات جديدة قبل أن تصبح جميع الميزات جاهزة للإنتاج. + +## الأهداف + +الأهداف الرئيسية لهذا العمل هي تمكين البيانات الوصفية حول الحقائق/البيانات: + +- **المعلومات الزمنية**: ربط الحقائق ببيانات وصفية تتعلق بالوقت + - متى اعتبرت حقيقة صحيحة + - متى أصبحت حقيقة صحيحة + - متى اكتشف أن حقيقة غير صحيحة + +- **الأصل/المصادر**: تتبع المصادر التي تدعم حقيقة ما + - "هذه الحقيقة مدعومة من المصدر X" + - ربط الحقائق بوثائقها الأصلية + +- **الموثوقية/الثقة**: تسجيل التأكيدات حول الحقيقة + - "الشخص P أعلن أن هذا صحيح" + - "الشخص Q يدعي أن هذا غير صحيح" + - تمكين تسجيل النقاط والتحقق من التعارض + +**الفرضية**: Reification (RDF-star / quoted triples) هي الآلية الرئيسية لتحقيق هذه النتائج، حيث تتطلب جميعها إجراء بيانات حول البيانات. + +## الخلفية + +للتعبير عن "تم اكتشاف حقيقة (تعرف أليس بوب) في 2024-01-15" أو "يدعم المصدر X الادعاء (يسبب Y Z)"، تحتاج إلى الرجوع إلى حافة كشيء يمكنك إجراء بيانات حوله. لا تدعم الثلاثيات القياسية هذا. + +### القيود الحالية + +يمكن للفئة `Value` الحالية في `trustgraph-base/trustgraph/schema/core/primitives.py` أن تمثل: +- عقد URI (`is_uri=True`) +- قيم حرفية (`is_uri=False`) + +يوجد الحقل `type` ولكنه لا يستخدم لتمثيل أنواع بيانات XSD. + +## التصميم التقني + +### ميزات RDF المدعومة + +#### الميزات الأساسية (المرتبطة بأهداف إعادة التعريف) + +ترتبط هذه الميزات بشكل مباشر بالأهداف الزمنية والأصل والموثوقية: + +1. **RDF 1.2 Quoted Triples (RDF-star)** + - حواف تشير إلى حواف أخرى + - يمكن أن تظهر الثلاثية كـ subject أو object في ثلاثية أخرى + - تمكن البيانات حول البيانات (reification) + - الآلية الأساسية لتعليق الحقائق الفردية + +2. **RDF Dataset / Named Graphs** + - دعم رسوم بيانية مسماة متعددة داخل مجموعة بيانات + - يتم تحديد كل رسم بياني بواسطة IRI + - الانتقال من ثلاثيات (s, p, o) إلى أرباع (s, p, o, g) + - يتضمن الرسم البياني الافتراضي بالإضافة إلى رسم بياني مسمى واحد أو أكثر + - يمكن أن يكون IRI الرسم البياني subject في البيانات، على سبيل المثال: + ``` + "2024-01-15" + "high" + ``` + - ملاحظة: الرسوم البيانية المسماة ميزة منفصلة عن إعادة التعريف. لها استخدامات تتجاوز تعليق البيانات (التقسيم، التحكم في الوصول، تنظيم مجموعة البيانات) ويجب اعتبارها قدرة متميزة. + +3. **Blank Nodes** (دعم محدود) + - عقد مجهولة الهوية بدون URI عالمي + - مدعوم من أجل التوافق عند تحميل بيانات RDF خارجية + - **حالة محدودة**: لا توجد ضمانات بشأن الهوية المستقرة بعد التحميل + - ابحث عنها عبر استعلامات wildcard (تطابق عن طريق الاتصالات، وليس عن طريق المعرف) + - ليست ميزة أساسية - لا تعتمد على معالجة دقيقة لعقد فارغة + +#### إصلاحات فرعية (تغيير جذري للإصدار 2.0) + +هذه الميزات ليست مرتبطة بشكل مباشر بأهداف إعادة التعريف ولكنها تحسينات قيمة يجب تضمينها أثناء إجراء تغييرات جذرية: + +4. **Literal Datatypes** + - استخدام الحقل `type` بشكل صحيح لأنواع بيانات XSD + - أمثلة: xsd:string, xsd:integer, xsd:dateTime، إلخ. + - يحل مشكلة حالية: لا يمكن تمثيل التواريخ أو الأعداد الصحيحة بشكل صحيح + +5. **Language Tags** + - دعم سمات اللغة على الحرفيات (`@en`, `@fr`, إلخ) + - ملاحظة: تحتوي الحرفية على إما علامة لغة أو نوع بيانات، وليس كلاهما (باستثناء `rdf:langString`) + - مهم لحالات الاستخدام المتعلقة بالذكاء الاصطناعي/اللغات المتعددة + +### نماذج البيانات + +#### Term (تغيير من Value) + +سيتم إعادة تسمية الفئة `Value` إلى `Term` لتعكس بشكل أفضل المصطلحات الخاصة بـ RDF. تخدم عملية إعادة التسمية هذه غرضين: +1. توافق التسمية مع مفاهيم RDF (يمكن أن يكون "Term" IRI أو عقدة فارغة أو حرفية أو ثلاثية مقتبسة - وليس مجرد "value") +2. إجبار مراجعة التعليمات البرمجية عند واجهة التغيير الجذري - أي تعليمات برمجية لا تزال تشير إلى `Value` ستظهر بشكل واضح أنها معطلة وتحتاج إلى التحديث + +يمكن أن يمثل Term: + +- **IRI/URI** - عقدة/مورد مسماة +- **Blank Node** - عقدة مجهولة الهوية ذات نطاق محلي +- **Literal** - قيمة بيانات مع إما: + - نوع بيانات (XSD type)، أو + - علامة لغة +- **Quoted Triple** - ثلاثية تستخدم كـ term (RDF 1.2) + +##### النهج المختار: فئة واحدة مع مُميز نوع + +تحدد متطلبات التسلسل الهيكل - هناك حاجة إلى مُميز نوع في التنسيق السلكي بغض النظر عن التمثيل في Python. الفئة الواحدة ذات نوع التمييز هي الأنسب وتتوافق مع نمط `Value` الحالي. + +توفر رموز النوع أحادية الحرف تسلسلًا مضغوطًا: + +```python +from dataclasses import dataclass + +# ثوابت أنواع Term +IRI = "i" # عقدة URI +BLANK = "b" # عقدة فارغة +LITERAL = "l" # قيمة حرفية +TRIPLE = "t" # ثلاثية مقتبسة (RDF 1.2) + +@dataclass +class Term: + type: str = "" # واحد من: IRI, BLANK, LITERAL, TRIPLE + + # لـ مصطلحات IRI (type == IRI) + iri: str = "" + + # لـ عقد فارغة (type == BLANK) + id: str = "" + + # لـ الحرفيات (type == LITERAL) + value: str = "" + datatype: str = "" # URI لنوع بيانات XSD (مستبعدة مع اللغة) + language: str = "" # علامة لغة (مستبعدة مع نوع البيانات) + + # لـ ثلاثيات مقتبسة (type == TRIPLE) + triple: "Triple | None" = None +``` + +أمثلة على الاستخدام: + +```python +# مصطلح IRI +node = Term(type=IRI, iri="http://example.org/Alice") + +# حرفية مع نوع بيانات +age = Term(type=LITERAL, value="42", datatype="xsd:integer") + +# حرفية مع علامة لغة +label = Term(type=LITERAL, value="Hello", language="en") + +# عقدة فارغة +anon = Term(type=BLANK, id="_:b1") + +# ثلاثية مقتبسة (بيانات حول بيانات) +inner = Triple( + s=Term(type=IRI, iri="http://example.org/Alice"), + p=Term(type=IRI, iri="http://example.org/knows"), + o=Term(type=IRI, iri="http://example.org/Bob"), +) +reified = Term(type=TRIPLE, triple=inner) +``` + +#### البدائل التي تم أخذها في الاعتبار + +**الخيار B: اتحاد الفئات المتخصصة** (`Term = IRI | BlankNode | Literal | QuotedTriple`) +- مرفوض: لا يزال التسلسل يحتاج إلى مُميز نوع، مما يضيف تعقيدًا + +**الخيار C: فئة أساسية مع فئات فرعية** +- مرفوض: نفس مشكلة التسلسل، بالإضافة إلى تعقيدات وراثة dataclass + +#### Triple / Quad + +تكتسب الفئة `Triple` حقل اختياري للرسم البياني ليصبح أربعة: + +```python +@dataclass +class Triple: + s: Term | None = None # Subject + p: Term | None = None # Predicate + o: Term | None = None # Object + g: str | None = None # اسم الرسم البياني (IRI)، None = الرسم البياني الافتراضي +``` + +قرارات التصميم: +- **اسم الحقل**: `g` لضمان الاتساق مع `s`, `p`, `o` +- **اختياري**: `None` يعني الرسم البياني الافتراضي (غير المسمى) +- **النوع**: سلسلة عادية (IRI) بدلاً من Term + - أسماء الرسم البياني هي دائمًا IRIs + - تم استبعاد العقد الفارغة كأسماء للرسوم البيانية (مربكة جدًا) + - لا حاجة إلى آليات Term الكاملة + +لاحظ أن اسم الفئة يظل `Triple` حتى لو كانت ثلاثية الآن. هذا يتجنب التغييرات الجذرية و "triple" هي لا تزال المصطلحات الشائعة. السياق البياني هو بيانات وصفية حول مكان وجود الثلاثية. + +### أنماط استعلام مرشحة + +يقبل محرك الاستعلام الحالي مجموعات من مصطلحات S, P, O. مع ثلاثيات مقتبسة، تصبح الثلاثية نفسها مصطلحًا صالحًا في هذه المواضع. فيما يلي أنماط استعلام مرشحة تدعم الأهداف الأصلية. + +#### معاني معلمات الرسم البياني + +باتباع اصطلاحات SPARQL للتوافق مع الإصدارات السابقة: + +- **تم حذف `g` / None**: استعلام للرسم البياني الافتراضي فقط +- **`g` = IRI محدد**: استعلام لهذا الرسم البياني المسمى فقط +- **`g` = حرف جاموسي / `*`**: استعلام عبر جميع الرسوم البيانية (مكافئ لـ SPARQL + `GRAPH ?g { ... }`) + +هذا يحافظ على بساطة الاستعلامات البسيطة ويجعل استعلامات الرسم البياني المسماة اختيارية. + +تدعم الاستعلامات عبر الرسوم البيانية (g=حرف جاموسي). يحتوي مخطط Cassandra على جداول مخصصة (SPOG, POSG, OSPG) حيث g هو عمود تجميع بدلاً من مفتاح التقسيم، مما يتيح استعلامات فعالة عبر جميع الرسوم البيانية. + +#### استعلامات زمنية + +**ابحث عن جميع الحقائق التي تم اكتشافها بعد تاريخ معين:** +``` +S: ? # أي ثلاثية مقتبسة +P: +O: > "2024-01-15"^^xsd:date # مقارنة التاريخ +``` + +**ابحث عن الوقت الذي اعتبرت فيه حقيقة صحيحة:** +``` +S: << >> # ثلاثية مقتبسة كـ subject +P: +O: ? # يعيد التاريخ +``` + +**ابحث عن الحقائق التي تبين أنها خاطئة:** +``` +S: ? # أي ثلاثية مقتبسة +P: +O: ? # له أي قيمة (موجود) +``` + +#### استعلامات الأصل + +**ابحث عن جميع الحقائق التي يدعمها مصدر معين:** +``` +S: ? # أي ثلاثية مقتبسة +P: +O: +``` + +**ابحث عن المصادر التي تدعم حقيقة معينة:** +``` +S: << >> # ثلاثية مقتبسة كـ subject +P: +O: ? # يعيد IRIs المصدر +``` + +#### استعلامات الموثوقية + +**ابحث عن التأكيدات التي أعلن شخص ما أنها صحيحة:** +``` +S: ? # أي ثلاثية مقتبسة +P: +O: +``` + +**ابحث عن التأكيدات المتعارضة (نفس الحقيقة، موثوقية مختلفة):** +``` +# الاستعلام الأول: الحقائق التي أعلنت صحتها +S: ? +P: +O: ? + +# الاستعلام الثاني: الحقائق التي أعلنت أنها خاطئة +S: ? +P: +O: ? + +# منطق التطبيق: ابحث عن تقاطع الـ subjects +``` + +**ابحث عن الحقائق التي تقل فيها درجة الثقة عن حد معين:** +``` +S: ? +P: +O: [threshold] +``` + +### حد تخزين المتجهات + +تستخدم مخازن المتجهات دائمًا IRIs فقط: +- لا توجد حواف (ثلاثيات مقتبسة) +- لا توجد قيم حرفية +- لا توجد عقد فارغة + +هذا يبقي تخزين المتجهات بسيطًا - يتعامل مع التشابه الدلالي للكائنات المسماة. يتعامل هيكل الرسم البياني مع العلاقات وإعادة التعريف والبيانات الوصفية. لا تعقد الثلاثيات المقتبسة والرسوم البيانية المسماة عمليات المتجهات. + +## اعتبارات الأمان + +الرسوم البيانية المسماة ليست ميزة أمان. تظل المستخدمون والمجموعات هي حدود الأمان. الرسوم البيانية المسماة مخصصة لتنظيم البيانات فقط وليست لإعادة التعريف. + +## اعتبارات الأداء + +- يمكن أن تضيف الثلاثيات المقتبسة عمق التداخل - قد تؤثر على أداء الاستعلام +- هناك حاجة إلى استراتيجيات فهرسة الرسم البياني المسماة للاستعلامات الفعالة الموجهة للرسم البياني +- يجب أن يستوعب تصميم مخطط Cassandra تخزين الأربعة بكفاءة + +### واجهة مستخدم مخزن المتجهات + +دائمًا ما تشير مخازن المتجهات إلى IRIs فقط: +- لا توجد حواف (ثلاثيات مقتبسة) +- لا توجد قيم حرفية +- لا توجد عقد فارغة + +هذا يبقي مخزن المتجهات بسيطًا - يتعامل مع التشابه الدلالي للكائنات المسماة. يتعامل هيكل الرسم البياني مع العلاقات وإعادة التعريف والبيانات الوصفية. لا تعقد الثلاثيات المقتبسة والرسوم البيانية المسماة عمليات المتجهات. + +## استراتيجية الاختبار + +استخدم استراتيجية الاختبار الحالية. نظرًا لأن هذا تغيير جذري، ركز بشكل كبير على مجموعة الاختبار الشاملة للتحقق من أن الهياكل الجديدة تعمل بشكل صحيح عبر جميع المكونات. + +## خطة الترحيل + +- 2.0 هو إصدار جذري؛ لا توجد توافقية مع الإصدارات السابقة مطلوبة +- قد تتطلب البيانات الحالية ترحيلًا إلى مخطط جديد (سيتم تحديده بناءً على التصميم النهائي) +- ضع في اعتبارك أدوات الترحيل لتحويل الثلاثيات الموجودة + +## أسئلة مفتوحة + +- **العقد الفارغة**: تم تأكيد الدعم المحدود. قد تحتاج إلى تحديد استراتيجية skolemization (إنشاء IRIs عند التحميل أو الحفاظ على معرفات العقد الفارغة). +- **بناء جملة الاستعلام**: ما هي البنية النحوية الملموسة لتحديد الثلاثيات المقتبسة في الاستعلامات؟ تحتاج إلى تعريف واجهة برمجة تطبيقات الاستعلام. +- ~~**مفردات السمة**~~: تم الحل. أي عناصر من المفردات RDF الصالحة مسموح بها، بما في ذلك العناصر المخصصة التي يحددها المستخدم. افتراضات قليلة جدًا عن صلاحية RDF. +- ~~**تأثير مستودع المتجهات**~~: تم الحل. تشير مستودعات المتجهات دائمًا إلى IRIs فقط - لا توجد حواف أو قيم حرفية أو عقد فارغة. لا تؤثر الثلاثيات المقتبسة وإعادة التعريف على مستودع المتجهات. +- ~~**دلالات الرسم البياني المسماة**~~: تم الحل. الاستعلامات افتراضيًا هي الرسم البياني الافتراضي (تتوافق مع سلوك SPARQL، متوافقة مع الإصدارات السابقة). مطلوب معلمة رسم بياني صريحة للاستعلام عن الرسوم البيانية المسماة أو جميع الرسوم البيانية. + +## المراجع + +- [RDF 1.2 Concepts](https://www.w3.org/TR/rdf12-concepts/) +- [RDF-star and SPARQL-star](https://w3c.github.io/rdf-star/) +- [RDF Dataset](https://www.w3.org/TR/rdf11-concepts/#section-dataset) \ No newline at end of file diff --git a/docs/tech-specs/graph-contexts.es.md b/docs/tech-specs/graph-contexts.es.md new file mode 100644 index 00000000..4dc72e7e --- /dev/null +++ b/docs/tech-specs/graph-contexts.es.md @@ -0,0 +1,386 @@ +# Especificación Técnica de Contextos de Grafos + +## Resumen + +Esta especificación describe los cambios en los primitivos de grafos centrales de TrustGraph para +alinearse con RDF 1.2 y admitir la semántica completa del conjunto de datos RDF. Este es un +cambio importante para la serie de versiones 2.x. + +### Versionamiento + +- **2.0**: Lanzamiento para adoptantes tempranos. Características principales disponibles, + puede que no esté completamente lista para producción. +- **2.1 / 2.2**: Lanzamiento de producción. Estabilidad y completitud validadas. + +La flexibilidad en cuanto a la madurez es intencional: los adoptantes tempranos pueden acceder a nuevas +capacidades antes de que todas las funciones estén listas para producción. + +## Objetivos + +Los objetivos principales de este trabajo son habilitar metadatos sobre hechos/afirmaciones: + +- **Información temporal**: Asociar hechos con metadatos de tiempo + - Cuándo se creyó que un hecho era verdadero + - Cuándo un hecho se volvió verdadero + - Cuándo se descubrió que un hecho era falso + +- **Origen/Fuentes**: Realizar un seguimiento de las fuentes que respaldan un hecho + - "Este hecho fue respaldado por la fuente X" + - Enlazar los hechos con sus documentos de origen + +- **Veracidad/Confianza**: Registrar afirmaciones sobre la verdad + - "La persona P afirmó que esto era cierto" + - "La persona Q afirma que esto es falso" + - Habilitar la puntuación de confianza y la detección de conflictos + +**Hipótesis**: La reificación (RDF-star / triples con comillas) es el mecanismo clave +para lograr estos resultados, ya que todos requieren hacer afirmaciones sobre afirmaciones. + +## Antecedentes + +Para expresar "el hecho (Alice conoce a Bob) se descubrió el 2024-01-15" o +"la fuente X respalda la afirmación (Y causa Z)", necesita referenciar un borde +como algo sobre lo cual se pueden hacer afirmaciones. Los triples estándar no admiten esto. + +### Limitaciones actuales + +La clase `Value` actual en `trustgraph-base/trustgraph/schema/core/primitives.py` +puede representar: +- Nodos URI (`is_uri=True`) +- Valores literales (`is_uri=False`) + +El campo `type` existe, pero no se utiliza para representar los tipos de datos XSD. + +## Diseño técnico + +### Características de RDF a admitir + +#### Características principales (relacionadas con los objetivos de reificación) + +Estas características están directamente relacionadas con los objetivos temporales, de origen y de veracidad: + +1. **RDF 1.2 Triples con comillas (RDF-star)** + - Bordes que apuntan a otros bordes + - Un triple puede aparecer como sujeto u objeto de otro triple + - Permite hacer afirmaciones sobre afirmaciones (reificación) + - Mecanismo central para anotar hechos individuales + +2. **Conjunto de datos RDF / Grafos con nombre** + - Soporte para múltiples grafos con nombre dentro de un conjunto de datos + - Cada grafo identificado por un IRI + - Pasa de triples (s, p, o) a cuads (s, p, o, g) + - Incluye un grafo predeterminado más cero o más grafos con nombre + - El IRI del grafo puede ser un sujeto en las afirmaciones, por ejemplo: + ``` + "2024-01-15" + "high" + ``` + - Nota: Los grafos con nombre son una característica separada de la reificación. Tienen + usos más allá de la anotación de afirmaciones (particionamiento, control de acceso, organización del conjunto de datos) + y deben tratarse como una capacidad distinta. + +3. **Nodos vacíos** (Soporte limitado) + - Nodos anónimos sin un URI global + - Compatible al cargar datos RDF externos + - **Estado limitado**: No hay garantías sobre la identidad estable después de la carga + - Encontrarlos a través de consultas comodín (coincidencia por conexiones, no por ID) + - No es una característica de primera clase: no confíe en el manejo preciso de nodos vacíos. + +#### Correcciones oportunistas (cambio importante de la versión 2.0) + +Estas características no están directamente relacionadas con los objetivos de la reificación, pero son +mejoras valiosas a incluir al realizar cambios importantes: + +4. **Tipos de literales** + - Utilice correctamente el campo `type` para los tipos de datos XSD + - Ejemplos: xsd:string, xsd:integer, xsd:dateTime, etc. + - Corrige la limitación actual: no se pueden representar fechas o enteros correctamente. + +5. **Etiquetas de idioma** + - Soporte para atributos de idioma en literales (por ejemplo, @en, @fr) + - Nota: un literal tiene una etiqueta de idioma O un tipo de datos, no ambos + (excepto para rdf:langString) + - Importante para casos de uso de IA/multilingües. + +### Modelos de datos + +#### Término (cambiar de Value) + +La clase `Value` se renombrará a `Term` para reflejar mejor la terminología de RDF. +Este cambio de nombre tiene dos propósitos: +1. Alinea la nomenclatura con los conceptos de RDF (un "Término" puede ser un IRI, literal, nodo vacío o triple con comillas, + no solo un "valor") +2. Fuerza la revisión del código en la interfaz de cambio importante: cualquier código que aún haga referencia a `Value` + se considera roto y debe actualizarse. + +Un Término puede representar: + +- **IRI/URI**: un nodo/recurso con nombre +- **Nodo vacío**: un nodo anónimo con alcance local +- **Literal**: un valor de datos con: + - Un tipo de datos (tipo XSD), O + - Una etiqueta de idioma +- **Triple con comillas**: un triple utilizado como término (RDF 1.2) + +##### Enfoque elegido: Clase única con discriminador de tipo + +Los requisitos de serialización impulsan la estructura: se necesita un discriminador de tipo en el formato de cable +independientemente de la representación de Python. Una clase única con un campo de tipo es la opción natural y se alinea con la +patrón `Value` actual. + +Los códigos de tipo de un solo carácter proporcionan una serialización compacta: + +```python +from dataclasses import dataclass + +# Constantes de tipo de término +IRI = "i" # Nodo IRI/URI +BLANK = "b" # Nodo vacío +LITERAL = "l" # Valor literal +TRIPLE = "t" # Triple con comillas (RDF 1.2) + +@dataclass +class Term: + type: str = "" # Uno de: IRI, BLANK, LITERAL, TRIPLE + + # Para términos IRI (type == IRI) + iri: str = "" + + # Para nodos vacíos (type == BLANK) + id: str = "" + + # Para literales (type == LITERAL) + value: str = "" + datatype: str = "" # URI de tipo de datos XSD (mutuamente excluyente con el idioma) + language: str = "" # Etiqueta de idioma (mutuamente excluyente con el tipo de datos) + + # Para triples con comillas (type == TRIPLE) + triple: "Triple | None" = None +``` + +Ejemplos de uso: + +```python +# Término IRI +node = Term(type=IRI, iri="http://example.org/Alice") + +# Literal con tipo de datos +age = Term(type=LITERAL, value="42", datatype="xsd:integer") + +# Literal con etiqueta de idioma +label = Term(type=LITERAL, value="Hello", language="en") + +# Nodo vacío +anon = Term(type=BLANK, id="_:b1") + +# Triple con comillas (afirmación sobre una afirmación) +inner = Triple( + s=Term(type=IRI, iri="http://example.org/Alice"), + p=Term(type=IRI, iri="http://example.org/knows"), + o=Term(type=IRI, iri="http://example.org/Bob"), +) +reified = Term(type=TRIPLE, triple=inner) +``` + +##### Alternativas consideradas + +**Opción B: Unión de clases especializadas** (`Term = IRI | BlankNode | Literal | QuotedTriple`) +- Rechazada: La serialización aún necesitaría un discriminador de tipo, lo que agregaría complejidad. + +**Opción C: Clase base con subclases** +- Rechazada: El mismo problema de serialización, además de peculiaridades de la herencia de dataclass. + +#### Triple / Cuad + +La clase `Triple` gana un campo de grafo opcional para convertirse en un cuad: + +```python +@dataclass +class Triple: + s: Term | None = None # Sujeto + p: Term | None = None # Predicado + o: Term | None = None # Objeto + g: str | None = None # Nombre del grafo (IRI), None = grafo predeterminado +``` + +Decisiones de diseño: +- **Nombre del campo**: `g` para la coherencia con `s`, `p`, `o` +- **Opcional**: `None` significa el grafo predeterminado (sin nombre) +- **Tipo**: Cadena simple (IRI) en lugar de Term + - Los nombres de los grafos siempre son IRIs + - Los nodos vacíos como nombres de grafos se descartaron (demasiado confusos) + - No es necesario el conjunto completo de mecanismos de Term + +Nota: El nombre de la clase permanece `Triple` incluso si técnicamente es un cuad ahora. +Esto evita la alteración y la terminología "triple" todavía es la terminología común. El contexto del grafo es +metadatos sobre dónde vive el triple. + +### Patrones de consulta candidatos + +El motor de consulta actual acepta combinaciones de términos S, P, O. Con los triples con comillas, +un triple en sí mismo se convierte en un término válido en esas posiciones. A continuación, se presentan patrones de consulta +candidatos que admiten los objetivos originales. + +#### Semántica de parámetros de grafo + +Siguiendo las convenciones de SPARQL para la compatibilidad hacia atrás: + +- **`g` omitido / None**: Consulta solo el grafo predeterminado +- **`g` = IRI específico**: Consulta solo ese grafo con nombre +- **`g` = comodín / `*`**: Consulta en todos los grafos (equivalente a `GRAPH ?g { ... }` de SPARQL) + +Esto mantiene las consultas simples simples y hace que las consultas de grafos con nombre sean opcionales. + +Las consultas entre grafos (g=comodín) se admiten completamente. El esquema de Cassandra incluye tablas dedicadas (SPOG, POSG, OSPG) +donde g es una columna de agrupación, en lugar de una clave de partición, lo que permite consultas eficientes en todos los grafos. + +#### Consultas temporales + +**Encontrar todos los hechos descubiertos después de una fecha determinada:** +``` +S: ? # cualquier triple con comillas +P: +O: > "2024-01-15"^^xsd:date # comparación de fecha +``` + +**Encontrar cuándo se creyó que un hecho era verdadero:** +``` +S: << >> # triple con comillas como sujeto +P: +O: ? # devuelve la fecha +``` + +**Encontrar los hechos que se descubrió que eran falsos:** +``` +S: ? # cualquier triple con comillas +P: +O: ? # tiene cualquier valor (existe) +``` + +#### Consultas de origen + +**Encontrar todos los hechos respaldados por una fuente específica:** +``` +S: ? # cualquier triple con comillas +P: +O: +``` + +**Encontrar qué fuentes respaldan un hecho específico:** +``` +S: << >> # triple con comillas como sujeto +P: +O: ? # devuelve las IRIs de la fuente +``` + +#### Consultas de veracidad + +**Encontrar las afirmaciones que una persona marcó como verdaderas:** +``` +S: ? # cualquier triple con comillas +P: +O: +``` + +**Encontrar las afirmaciones conflictivas (el mismo hecho, diferente veracidad):** +``` +# Primera consulta: hechos afirmados como verdaderos +S: ? +P: +O: ? + +# Segunda consulta: hechos afirmados como falsos +S: ? +P: +O: ? + +# Lógica de la aplicación: encontrar la intersección de los sujetos +``` + +**Encontrar los hechos con una puntuación de confianza por debajo del umbral:** +``` +S: ? # cualquier triple con comillas +P: +O: < 0.5 # comparación numérica +``` + +### Arquitectura + +Se requieren cambios significativos en varios componentes: + +#### Este repositorio (trustgraph) + +- **Primitivos del esquema** (`trustgraph-base/trustgraph/schema/core/primitives.py`) + - `Value` → `Term` cambio de nombre + - Nueva estructura de `Term` con discriminador de tipo + - `Triple` gana el campo `g` para el contexto del grafo + +- **Traductores de mensajes** (`trustgraph-base/trustgraph/messaging/translators/`) + - Actualizaciones para las nuevas estructuras de `Term` y `Triple` + +- **Componentes de puerta de enlace** + - Manejar nuevas estructuras de `Term` y cuádruple + +- **Núcleos de conocimiento** + - ... + +- **Pruebas** + - ... + +Esto se deja para futuras implementaciones. + +- **Vector store boundary** + - ... + +Esto se deja para futuras implementaciones. + +## Consideraciones de seguridad + +Los grafos con nombre no son una característica de seguridad. Los usuarios y las colecciones siguen siendo los límites de seguridad. +Los grafos con nombre son puramente para la organización de datos y el soporte de la reificación. + +## Consideraciones de rendimiento + +- Los triples con comillas agregan profundidad de anidamiento; esto puede afectar el rendimiento de las consultas. +- Se necesitan estrategias de indexación para consultas con ámbito de grafo. +- El diseño del esquema de Cassandra deberá acomodar el almacenamiento de cuádruples de forma eficiente. + +### Límite del almacén vectorial + +Los almacenes vectoriales siempre hacen referencia a IRIs: +- Nunca bordes (triples con comillas) +- Nunca valores literales +- Nunca nodos vacíos + +Esto mantiene el almacén vectorial simple; se encarga de la similitud semántica de las entidades con nombre. La estructura del grafo maneja las relaciones, la reificación y los metadatos. Los triples con comillas y los grafos con nombre no complican las operaciones vectoriales. + +## Estrategia de pruebas + +Utilice la estrategia de prueba existente. Dado que esta es una versión importante, se prestará especial atención al +conjunto de pruebas de extremo a extremo para validar que las nuevas estructuras funcionan correctamente en todos los componentes. + +## Plan de migración + +- La versión 2.0 es una versión importante; no se requiere compatibilidad con versiones anteriores +- Los datos existentes pueden necesitar migrarse al nuevo esquema (por determinarse según el diseño final) +- Considere herramientas de migración para convertir triples existentes + +## Preguntas abiertas + +- **Nodos vacíos**: Soporte limitado confirmado. Es posible que deba decidirse sobre una estrategia de skolemización (generar IRIs + al cargar o preservar los ID de nodos vacíos). +- **Sintaxis de consulta**: ¿Cuál es la sintaxis concreta para especificar triples con comillas en las consultas? Debe definirse + la API de consulta. +- ~~**Vocabulario de predicados**~~: Resuelto. Se permiten todos los predicados RDF válidos, incluidos los personalizados definidos por el usuario. + Supuestos mínimos sobre la validez de RDF. Muy pocos valores bloqueados (por ejemplo, `rdfs:label` se utiliza en algunos lugares). + Estrategia: evite bloquear cualquier cosa a menos que sea absolutamente necesario. +- ~~**Impacto del almacén vectorial**~~: Resuelto. Los almacenes vectoriales siempre apuntan a IRIs. + solo; nunca bordes, literales o nodos vacíos. Los triples con comillas y la reificación no afectan al almacén vectorial. +- ~~**Semántica del grafo con nombre**~~: Resuelta. Las consultas predeterminadas son para el grafo predeterminado (coincide con el comportamiento de SPARQL, + compatible con versiones anteriores). Se requiere un parámetro de grafo explícito para consultar grafos con nombre o todos los grafos. + +## Referencias + +- [Conceptos RDF 1.2](https://www.w3.org/TR/rdf12-concepts/) +- [RDF-star y SPARQL-star](https://w3c.github.io/rdf-star/) +- [Conjunto de datos RDF](https://www.w3.org/TR/rdf11-concepts/#section-dataset) \ No newline at end of file diff --git a/docs/tech-specs/graph-contexts.he.md b/docs/tech-specs/graph-contexts.he.md new file mode 100644 index 00000000..ffa6e929 --- /dev/null +++ b/docs/tech-specs/graph-contexts.he.md @@ -0,0 +1,316 @@ +# מפרט טכני של הקשרים בגרף + +## סקירה כללית + +מפרט זה מתאר שינויים בפרימיטיבים הבסיסיים של הגרף ב-TrustGraph, +כדי להתאים ל-RDF 1.2 ולתמוך בסמנטיקה מלאה של סט נתונים RDF. +זוהי שינוי משמעותי עבור סדרת השחרורים 2.x. + +### גרסאות + +- **2.0**: גרסה למתקדמים. תכונות ליבה זמינות, ייתכן שאינן + מוכנות לחלוטין לשימוש בייצור. +- **2.1 / 2.2**: גרסת ייצור. יציבות ושלמות אומתו. + +הגמישות בנוגע לבשלות היא מכוונת - משתמשים מתקדמים יכולים לגשת +ליכולות חדשות לפני שכל התכונות מוכנות לשימוש בייצור. + +## מטרות + +המטרות העיקריות של עבודה זו הן לאפשר מטא-נתונים על עובדות/הצהרות: + +- **מידע זמני**: קשר עובדות עם מטא-נתונים של זמן + - מתי עובדה נחשבה לנכונה + - מתי עובדה הפכה לנכונה + - מתי עובדה התגלתה כלא נכונה + +- **מקורות/מקורות**: מעקב אחר מקורות התומכים בעובדה + - "עובדה זו נתמכה על ידי המקור X" + - קישור עובדות למסמכי המקור שלהן + +- **נכונות/אמינות**: תיעוד הצהרות על אמת + - "האדם P טען שזה נכון" + - "האדם Q טוען שזה לא נכון" + - אפשרות לחישוב ציון אמינות וגילוי סתירות + +**השערה**: Reification (RDF-star / משולשות מצוטטות) הוא המנגנון העיקרי +לשם השגת תוצאות אלה, מכיוון שכולן דורשות הצהרות על הצהרות. + +## רקע + +כדי להביע "העובדה (אליס יודעת את בוב) התגלתה ב-2024-01-15" או +"מקור X תומך בטענה (Y גורם ל-Z)", אתה צריך להתייחס לקצה +כאל דבר שאפשר להצהיר עליו. משולשות סטנדרטיים אינם תומכים בכך. + +### מגבלות נוכחיות + +המחלקת `Value` הנוכחית ב-`trustgraph-base/trustgraph/schema/core/primitives.py` +יכולה לייצג: +- צומתי URI (`is_uri=True`) +- ערכים מילוליים (`is_uri=False`) + +השדה `type` קיים אך אינו משמש לייצוג טיפוסי נתונים של XSD. + +## עיצוב טכני + +### תכונות RDF לתמיכה + +#### תכונות ליבה (קשור למטרות ה-Reification) + +תכונות אלו קשורות ישירות למטרות הזמן, המקור והנכונות: + +1. **משולשות מצוטטות של RDF 1.2 (RDF-star)** + - קצוות המצביעים על קצוות אחרים + - משולש יכול להופיע כנושא או כאובייקט של משולש אחר + - מאפשר הצהרות על הצהרות (reification) + - מנגנון ליבה לסימון עובדות בודדות + +2. **סט נתונים RDF / גרפים בעלי שם** + - תמיכה במספר גרפים בעלי שם בתוך סט נתונים + - כל גרף מזוהה על ידי IRI + - מעבר משלשות (s, p, o) לארבעיות (s, p, o, g) + - כולל גרף ברירת מחדל ואחד או יותר גרפים בעלי שם + - ניתן להשתמש ב-IRI של הגרף כנושא בהצהרות, לדוגמה: + ``` + "2024-01-15" + "high" + ``` + - הערה: גרפים בעלי שם הם תכונה נפרדת מ-reification. יש להם + שימושים מעבר לסימון הצהרות (מחיצה, בקרת גישה, ארגון סט נתונים) + ועליהם להתייחס אליהם כלי יכולת נפרדת. + +3. **צמתים ריקים** (תמיכה מוגבלת) + - צמתים אנונימיים ללא URI גלובלי + - נתמך לצורך תאימות בעת טעינת נתוני RDF חיצוניים + - **סטטוס מוגבל**: אין ערובות לזהות יציבה לאחר הטעינה + - ניתן למצוא אותם באמצעות שאילתות wildcard (התאמה לפי חיבורים, לא לפי מזהה) + - לא תכונה ראשית - אין להסתמך על טיפול מדויק בצמתים ריקים + +#### תיקונים הזדמנותיים (שינוי שבירה 2.0) + +תכונות אלה אינן קשורות ישירות למטרות ה-reification, אך הן שיפורים +חשובים שצריך לכלול בעת ביצוע שינויים שבירים: + +4. **טיפוסי מילוליים** + - שימוש נכון בשדה `type` עבור טיפוסי נתונים של XSD + - דוגמאות: xsd:string, xsd:integer, xsd:dateTime וכו' + - פותר מגבלה קיימת: לא ניתן לייצג תאריכים או מספרים שלמים כראוי + +5. **תגיות שפה** + - תמיכה בתכונות שפה על מילוליים (en, fr וכו') + - הערה: למילול יש תגית שפה או טיפוס נתונים, לא את שניהם + (מלבד rdf:langString) + - חשוב עבור מקרי שימוש בבינה מלאכותית/רב-לשוניים + +### מודלים של נתונים + +#### Term (שינוי שם מ-Value) + +המחלקת `Value` תשנה את שמה ל-`Term` כדי לשקף טוב יותר את המונחים של RDF. +שינוי שם זה משרת שני מטרות: +1. מיישר את שמות עם מושגים של RDF (ה- "Term" יכול להיות IRI, מילול, צומת ריק או משולש מצוטט - ולא רק "ערך") +2. גורם לסקירת קוד בממשק לשינוי השבירה - כל קוד שעדיין מתייחס ל-`Value` + נראה שבור באופן גלוי ויש לעדכן אותו + +Term יכול לייצג: + +- **IRI/URI** - צומת/משאב בעל שם +- **צומת ריק** - צומת אנונימי עם תחום מקומי +- **מילול** - ערך נתונים עם: + - טיפוס נתונים (טיפוס XSD), או + - תגית שפה +- **משולש מצוטט** - משולש המשמש כ-term (RDF 1.2) + +##### גישה שנבחרה: מחלקה אחת עם מפריד טיפוס + +דרישות הסתרה חשובות למבנה - מפריד טיפוס נחוץ +בפורמט ה-wire ללא קשר לייצוג ה-Python. מחלקה אחת עם שדה טיפוס היא +ההתאמה הטבעית ותואמת לדפוס ה-`Value` הנוכחי. + +קודים חד-תווים של טיפוסים מספקים הסתרה קומפקטית: + +```python +from dataclasses import dataclass + +# קבועים של סוג Term +IRI = "i" # צומת IRI/URI +BLANK = "b" # צומת ריק +LITERAL = "l" # ערך מילולי +TRIPLE = "t" # משולש מצוטט (RDF-star) + +@dataclass +class Term: + type: str = "" # אחד מ: IRI, BLANK, LITERAL, TRIPLE + + # עבור מונחי IRI (type == IRI) + iri: str = "" + + # עבור צמתים ריקים (type == BLANK) + id: str = "" + + # עבור מילויים (type == LITERAL) + value: str = "" + datatype: str = "" # טיפוס URI של XSD (בלעדי ל-language) + language: str = "" # תגית שפה (בלעדי ל-datatype) + + # עבור משולשות מצוטטות (type == TRIPLE) + triple: "Triple | None" = None +``` + +דוגמאות שימוש: + +```python +# מונח IRI +node = Term(type=IRI, iri="http://example.org/Alice") + +# מילול עם טיפוס נתונים +age = Term(type=LITERAL, value="42", datatype="xsd:integer") + +# מילול עם תגית שפה +label = Term(type=LITERAL, value="Hello", language="en") + +# צומת ריק +anon = Term(type=BLANK, id="_:b1") + +# משולש מצוטט (הצהרה על הצהרה) +inner = Triple( + s=Term(type=IRI, iri="http://example.org/Alice"), + p=Term(type=IRI, iri="http://example.org/knows"), + o=Term(type=IRI, iri="http://example.org/Bob"), +) +reified = Term(type=TRIPLE, triple=inner) +``` + +##### אלטרנטיבות שנשקלו + +**אפשרות B: איחוד של מחלקות מיוחדות** (`Term = IRI | BlankNode | Literal | QuotedTriple`) +- נדחה: הסתרה עדיין תצטרך מפריד טיפוס, מה שמוסיף מורכבות + +**אפשרות C: מחלקה בסיסית עם תת-מחלקה** +- נדחה: אותה בעיית הסתרה, בנוסף לבעיות ירושה של dataclass + +#### משולש / ארבעייה + +המחלקת `Triple` רוכשת שדה גרף אופציונלי כדי להפוך לארבעייה: + +```python +@dataclass +class Triple: + s: Term | None = None # נושא + p: Term | None = None # תכונה + o: Term | None = None # אובייקט + g: str | None = None # שם גרף (IRI), None = גרף ברירת מחדל +``` + +החלטות עיצוב: +- **שם שדה**: `g` לעקביות עם `s`, `p`, `o` +- **אופציונלי**: `None` פירושו הגרף כברירת מחדל (חסר שם) +- **סוג**: מחרוזת פשוטה (IRI) ולא Term + - שמות גרפים הם תמיד IRIs + - צמתים ריקים כשמות גרפים נשללו (מבלבלים) + - אין צורך במכניקת ה-Term המלאה + +שים לב: שם המחלקה נשאר `Triple` גם אם היא טכנית ארבעייה. +זה מונע שינויים ו"משולש" הוא עדיין המונח הנפוץ. הקונטקסט של הגרף +הוא מטא-נתונים לגבי היכן שוכנת השלישייה. + +### תבניות שאילתות מועמדות + +מנוע השאילתות הנוכחי מקבל שילובים של מונחי S, P, O. עם משולשות מצוטטות, +משולש בעצמו הופך ל-term חוקי בעמדות אלה. להלן תבניות שאילתות מועמדות +התומכות במטרות המקוריות. + +#### סמנטיקת פרמטר גרף + +בהתאם לקונבנציות SPARQL עבור תאימות לאחור: + +- **`g` מושמט / None**: שאילתא רק את הגרף כברירת מחדל +- **`g` = IRI ספציפי**: שאילתא רק את הגרף בעל השם הזה +- **`g` = wildcard / `*`**: שאילתא על פני כל הגרפים (שווה ערך ל-SPARQL + `GRAPH ?g { ... }`) + +זה שומר על שאילתות פשוטות כפשוטות ומאפשר שאילתות על גרפים בעלי +שמות כבחירה. + +שאילתות חוצות גרפים (g=wildcard) נתמכות במלואן. סכימת Cassandra +כוללת טבלאות ייעודיות (SPOG, POSG, OSPG) כאשר g הוא עמודת clustering +ולא מפתח מחיצה, המאפשר שאילתות יעילות על פני כל הגרפים. + +#### שאילתות זמניות + +**מצא את כל העובדות שהתגלו בתאריך 2024-01-15:** +``` +SELECT * FROM triples WHERE ?s p1 ?o1 . +``` + +#### שיקולי ביצועים + +- משולשות מצוטטות מוסיפות עומק קינון - עשויות להשפיע על ביצועי השאילתות +- אסטרטגיות אינדוקס לגרפים בעלי שם נחוצות עבור שאילתות יעילות מבוססות גרפים +- עיצוב סכימת Cassandra יצטרך להתאים אחסון ארבעיות ביעילות + +### גבולת מאגר וקטורי + +מאגרי וקטורים תמיד מתייחסים ל-IRIs בלבד: +- לעולם לא קצוות (משולשות מצוטטות) +- לעולם לא ערכים מילוליים +- לעולם לא צמתים ריקים + +זה שומר על מאגר הווקטורים פשוט - הוא מטפל בדמיון סמנטי של ישויות בעלות שם. +המבנה של הגרף מטפל ביחסים, reification ומטא-נתונים. משולשות מצוטטות +וגרפים בעלי שם אינם מסבכים פעולות וקטוריות. + +## שיקולי אבטחה + +גרפים בעלי שם אינם תכונה של אבטחה. משתמשים ואוספים הם גבולות האבטחה. +גרפים בעלי שם הם אך ורק עבור ארגון נתונים ו-reification תמיכה. + +## שיקולי ביצועים + +- משולשות מצוטטות מוסיפות עומק קינון - עשויות להשפיע על ביצועי השאילתות +- אסטרטגיות אינדוקס לגרפים בעלי שם נחוצות עבור שאילתות יעילות מבוססות גרפים +- עיצוב סכימת Cassandra יצטרך להתאים אחסון ארבעיות ביעילות + +### גבולת מאגר וקטורי + +מאגרי וקטורים תמיד מתייחסים ל-IRIs בלבד: +- לעולם לא קצוות (משולשות מצוטטות) +- לעולם לא ערכים מילוליים +- לעולם לא צמתים ריקים + +זה שומר על מאגר הווקטורים פשוט - הוא מטפל בדמיון סמנטי של ישויות בעלות שם. +המבנה של הגרף מטפל ביחסים, reification ומטא-נתונים. משולשות מצוטטות +וגרפים בעלי שם אינם מסבכים פעולות וקטוריות. + +## אסטרטגיית בדיקה + +השתמש באסטרטגיית הבדיקה הקיימת. מכיוון שזוהי גרסה שבירה, יש להתמקד +בבדיקות הקצה כדי לוודא שהמבנים החדשים עובדים כראוי בכל הרכיבים. + +## תוכנית העברה + +- 2.0 היא גרסה שבירה; אין צורך בתאימות לאחור +- ייתכן שיהיה צורך להעביר נתונים קיימים לסכימה חדשה (בהתאם לעיצוב הסופי) +- שקול כלי העברה להמרת משולשות קיימות + +## שאלות פתוחות + +- **צמתים ריקים**: תמיכה מוגבלת אושרה. ייתכן שיהיה צורך להחליט על + אסטרטגיית skolemization (ליצור IRIs בעת הטעינה, או לשמר מזהי צמתים ריקים). +- **תחביר שאילתא**: מהו התחביר הקונקרטי לציין משולשות מצוטטות + בשאלות? יש להגדיר את ממשק ה-API של השאילתא. +- ~~**אוצר מילים של תכונות**~~: נפתר. כל תכונות RDF חוקיות מותרות, + כולל מילים מוגדרות על ידי משתמש. הנחות מינימליות לגבי תוקף RDF. + אסטרטגיה: הימנע מנעילה אלא אם הכרחי לחלוטין. +- ~~**השפעה על מאגר הווקטורים**~~: נפתר. מאגרי וקטורים תמיד מצביעים על + IRIs בלבד - לעולם לא קצוות, מילויים או צמתים ריקים. משולשות מצוטטות + וגרפים בעלי שם אינם משפיעים על מאגר הווקטורים. +- ~~**סמנטיקת גרפים בעלי שם**~~: נפתר. שאילתות כברירת מחדל לגרף + כברירת מחדל (מתאים להתנהגות SPARQL, תואם לאחור). פרמטר גרף ספציפי + נדרש לשאילתא על גרפים בעלי שם או כל הגרפים. + +## הפניות + +- [מושגים של RDF 1.2](https://www.w3.org/TR/rdf12-concepts/) +- [RDF-star ו-SPARQL-star](https://w3c.github.io/rdf-star/) +- [סט נתונים RDF](https://www.w3.org/TR/rdf11-concepts/#section-dataset) \ No newline at end of file diff --git a/docs/tech-specs/graph-contexts.hi.md b/docs/tech-specs/graph-contexts.hi.md new file mode 100644 index 00000000..3bcd9036 --- /dev/null +++ b/docs/tech-specs/graph-contexts.hi.md @@ -0,0 +1,368 @@ +# ग्राफ संदर्भ तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ के मुख्य ग्राफ प्रिमिटिव में किए गए परिवर्तनों का वर्णन करता है ताकि +यह RDF 1.2 के अनुरूप हो और RDF डेटासेट के पूर्ण अर्थों का समर्थन कर सके। यह 2.x रिलीज़ श्रृंखला के लिए एक महत्वपूर्ण बदलाव है। + +### संस्करण + +- **2.0**: प्रारंभिक अपनाने वाला रिलीज़। मुख्य विशेषताएं उपलब्ध हैं, लेकिन यह पूरी तरह से + उत्पादन के लिए तैयार नहीं हो सकता है। +- **2.1 / 2.2**: उत्पादन रिलीज़। स्थिरता और पूर्णता की पुष्टि की गई है। + +परिपक्वता में लचीलापन जानबूझकर रखा गया है - प्रारंभिक अपनाने वाले नई +क्षमताओं तक पहुंच सकते हैं, भले ही सभी विशेषताएं उत्पादन के लिए पूरी तरह से तैयार न हों। + +## लक्ष्य + +इस कार्य के प्राथमिक लक्ष्य तथ्यों/कथनों के बारे में मेटाडेटा को सक्षम करना हैं: + +- **टेम्पोरल जानकारी**: तथ्यों को समय मेटाडेटा से जोड़ना + - जब किसी तथ्य को सत्य माना गया था + - जब कोई तथ्य सत्य हो गया + - जब किसी तथ्य को गलत साबित किया गया + +- **उत्पत्ति/स्रोत**: यह ट्रैक करना कि कौन से स्रोत किसी तथ्य का समर्थन करते हैं + - "यह तथ्य स्रोत X द्वारा समर्थित था" + - तथ्यों को उनके मूल दस्तावेजों से जोड़ना + +- **सत्यता/विश्वसनीयता**: सत्य के बारे में दावे रिकॉर्ड करना + - "व्यक्ति P ने कहा कि यह सत्य था" + - "व्यक्ति Q का दावा है कि यह गलत है" + - विश्वास स्कोरिंग और संघर्ष का पता लगाने को सक्षम करना + +**परिकल्पना**: पुन:पुनर्बलन (RDF-स्टार / उद्धृत ट्रिपल) वह प्रमुख तंत्र है +इन परिणामों को प्राप्त करने के लिए, क्योंकि सभी को कथनों के बारे में कथन करने की आवश्यकता होती है। + +## पृष्ठभूमि + +"यह तथ्य (एलिस बॉब को जानती है) 15 जनवरी, 2024 को खोजा गया था" या +"स्रोत X दावे (Y कारण Z है) का समर्थन करता है" को व्यक्त करने के लिए, आपको एक किनारे +का संदर्भ देना होगा जिसे आप कथनों के बारे में बात कर सकते हैं। मानक ट्रिपल इसका समर्थन नहीं करते हैं। + +### वर्तमान सीमाएं + +`trustgraph-base/trustgraph/schema/core/primitives.py` में वर्तमान `Value` वर्ग: +- URI नोड (`is_uri=True`) +- शाब्दिक मान (`is_uri=False`) + +`type` फ़ील्ड मौजूद है, लेकिन इसका उपयोग XSD डेटा प्रकारों को दर्शाने के लिए नहीं किया जाता है। + +## तकनीकी डिज़ाइन + +### समर्थित RDF विशेषताएं + +#### मुख्य विशेषताएं (पुन:पुनर्बलन लक्ष्यों से संबंधित) + +ये विशेषताएं अस्थायी, उत्पत्ति और सत्यता लक्ष्यों से सीधे संबंधित हैं: + +1. **RDF 1.2 उद्धृत ट्रिपल (RDF-स्टार)** + - किनारे जो अन्य किनारों की ओर इशारा करते हैं + - एक ट्रिपल एक ट्रिपल के विषय या वस्तु दोनों के रूप में दिखाई दे सकता है + - कथनों के बारे में कथन सक्षम करें (पुन:पुनर्बलन) + - व्यक्तिगत तथ्यों को एनोटेट करने का मुख्य तंत्र + +2. **RDF डेटासेट / नामित ग्राफ** + - एक डेटासेट के भीतर कई नामित ग्राफ का समर्थन + - प्रत्येक ग्राफ को एक IRI द्वारा पहचाना जाता है + - ट्रिपल (s, p, o) से क्वाड (s, p, o, g) में बदलाव + - एक डिफ़ॉल्ट ग्राफ प्लस शून्य या अधिक नामित ग्राफ शामिल हैं + - ग्राफ IRI कथनों में एक विषय हो सकता है, उदाहरण के लिए: + ``` + "2024-01-15" + "उच्च" + ``` + - ध्यान दें: नामित ग्राफ पुन:पुनर्बलन से अलग विशेषता है। उनके + कथन एनोटेशन (विभाजन, एक्सेस नियंत्रण, डेटासेट संगठन) से परे उपयोग हैं + और इसे एक अलग क्षमता के रूप में माना जाना चाहिए। + +3. **रिक्त नोड** (सीमित समर्थन) + - वैश्विक URI के बिना अनाम नोड + - बाहरी RDF डेटा लोड करते समय संगतता के लिए समर्थित + - **सीमित स्थिति**: लोडिंग के बाद स्थिर पहचान की कोई गारंटी नहीं + - वाइल्डकार्ड प्रश्नों के माध्यम से उनका पता लगाएं (कनेक्शन से मिलान करें, आईडी से नहीं) + - यह पहली श्रेणी की विशेषता नहीं है - सटीक रिक्त नोड हैंडलिंग पर भरोसा न करें। + +#### अवसरवादी सुधार (2.0 ब्रेकिंग परिवर्तन) + +ये विशेषताएं पुन:पुनर्बलन लक्ष्यों से सीधे संबंधित नहीं हैं, लेकिन +महत्वपूर्ण सुधार हैं जिन्हें ब्रेकिंग परिवर्तनों के दौरान शामिल किया जाना चाहिए: + +4. **शाब्दिक डेटा प्रकार** + - XSD डेटा प्रकारों के लिए `type` फ़ील्ड का ठीक से उपयोग करें + - उदाहरण: xsd:string, xsd:integer, xsd:dateTime, आदि। + - वर्तमान सीमा को ठीक करता है: तिथियों या पूर्णांकों को ठीक से दर्शाया नहीं जा सकता है। + +5. **भाषा टैग** + - स्ट्रिंग शाब्दिक पर भाषा विशेषताओं का समर्थन + - ध्यान दें: एक शाब्दिक में या तो एक भाषा टैग होता है या एक डेटा प्रकार, दोनों नहीं + (rdf:langString को छोड़कर) + - AI/बहुभाषी उपयोग के मामलों के लिए महत्वपूर्ण। + +### डेटा मॉडल + +#### टर्म (नाम बदलकर वैल्यू) + +`Value` वर्ग को बेहतर ढंग से RDF शब्दावली को दर्शाने के लिए `Term` में बदल दिया जाएगा। +इस नामकरण का दो उद्देश्य हैं: +1. यह नामकरण RDF अवधारणाओं के साथ संरेखित होता है (एक "टर्म" एक IRI, शाब्दिक, + रिक्त नोड या उद्धृत ट्रिपल हो सकता है - केवल एक "मान" नहीं)। +2. यह ब्रेकिंग परिवर्तन इंटरफ़ेस पर कोड समीक्षा को मजबूर करता है - कोई भी कोड जो अभी भी + `Value` को संदर्भित करता है, वह स्पष्ट रूप से टूटा हुआ है और इसे अपडेट करने की आवश्यकता है। + +एक टर्म का प्रतिनिधित्व किया जा सकता है: + +- **IRI/URI**: एक नामित नोड/संसाधन +- **रिक्त नोड**: स्थानीय दायरे वाला एक अनाम नोड +- **शाब्दिक**: एक डेटा मान जिसमें या तो: + - एक डेटा प्रकार (XSD प्रकार), या + - एक भाषा टैग +- **उद्धृत ट्रिपल**: एक ट्रिपल का उपयोग एक टर्म के रूप में किया जाता है (RDF 1.2) + +##### चुनी गई दृष्टिकोण: एकल वर्ग जिसमें प्रकार विभेदक है + +सीरियलाइज़ेशन आवश्यकताएं संरचना को चलाती हैं - वायर प्रारूप में एक प्रकार विभेदक की आवश्यकता होती है +चाहे पायथन प्रतिनिधित्व कुछ भी हो। एक एकल वर्ग जिसमें एक प्रकार फ़ील्ड प्राकृतिक है +और वर्तमान `Value` पैटर्न के साथ संरेखित है। + +एकल-अक्षर प्रकार कोड कॉम्पैक्ट सीरियलाइज़ेशन प्रदान करते हैं: + +```python +from dataclasses import dataclass + +# टर्म प्रकार स्थिरांक +IRI = "i" # IRI/URI नोड +BLANK = "b" # रिक्त नोड +LITERAL = "l" # शाब्दिक मान +TRIPLE = "t" # उद्धृत ट्रिपल (RDF-स्टार) + +@dataclass +class Term: + type: str = "" # इनमें से एक: IRI, BLANK, LITERAL, TRIPLE + + # IRI टर्म के लिए (type == IRI) + iri: str = "" + + # रिक्त नोड के लिए (type == BLANK) + id: str = "" + + # शाब्दिक के लिए (type == LITERAL) + value: str = "" + datatype: str = "" # XSD डेटा प्रकार URI (भाषा के साथ परस्पर अनन्य) + language: str = "" # भाषा टैग (डेटा प्रकार के साथ परस्पर अनन्य) + + # उद्धृत ट्रिपल के लिए (type == TRIPLE) + triple: "Triple | None" = None +``` + +उपयोग के उदाहरण: + +```python +# IRI टर्म +node = Term(type=IRI, iri="http://example.org/Alice") + +# डेटा प्रकार के साथ शाब्दिक +age = Term(type=LITERAL, value="42", datatype="xsd:integer") + +# भाषा टैग के साथ शाब्दिक +label = Term(type=LITERAL, value="नमस्ते", language="en") + +# रिक्त नोड +anon = Term(type=BLANK, id="_:b1") + +# उद्धृत ट्रिपल (कथन के बारे में कथन) +inner = Triple( + s=Term(type=IRI, iri="http://example.org/Alice"), + p=Term(type=IRI, iri="http://example.org/knows"), + o=Term(type=IRI, iri="http://example.org/Bob"), +) +reified = Term(type=TRIPLE, triple=inner) +``` + +##### विचार किए गए विकल्प + +**विकल्प B: विशिष्ट वर्गों का संघ** (`Term = IRI | BlankNode | Literal | QuotedTriple`) +- अस्वीकृत: सीरियलाइज़ेशन को अभी भी एक प्रकार विभेदक की आवश्यकता होगी, जो जटिलता जोड़ता है। + +**विकल्प C: बेस क्लास जिसमें सबक्लासेस हैं** +- अस्वीकृत: समान सीरियलाइज़ेशन समस्या, साथ ही डेटा क्लास इनहेरिटेंस की जटिलताएं। + +#### ट्रिपल / क्वाड + +`Triple` वर्ग में एक वैकल्पिक ग्राफ फ़ील्ड है ताकि यह क्वाड बन जाए: + +```python +@dataclass +class Triple: + s: Term | None = None # विषय + p: Term | None = None # विधेय + o: Term | None = None # वस्तु + g: str | None = None # ग्राफ नाम (IRI), None = डिफ़ॉल्ट ग्राफ +``` + +डिज़ाइन निर्णय: +- **फ़ील्ड नाम**: स्थिरता के लिए `g` को `s`, `p`, `o` के साथ +- **वैकल्पिक**: `None` का मतलब डिफ़ॉल्ट ग्राफ (अनटैग) +- **प्रकार**: पूर्ण `Term` तंत्र की आवश्यकता नहीं होने के कारण, केवल एक स्ट्रिंग (IRI) + - ग्राफ नाम हमेशा IRI होते हैं + - ग्राफ नाम के रूप में रिक्त नोड को खारिज कर दिया गया (बहुत भ्रमित करने वाला) + +ध्यान दें: `Triple` वर्ग का नाम `Quad` होने पर भी `Triple` रहता है। +यह अपव्यय से बचाता है और "ट्रिपल" अभी भी सामान्य शब्दावली है। ग्राफ संदर्भ +यह दर्शाता है कि ट्रिपल कहाँ स्थित है। + +### उम्मीदवार क्वेरी पैटर्न + +वर्तमान क्वेरी इंजन S, P, O टर्म के संयोजनों को स्वीकार करता है। उद्धृत +ट्रिपल के साथ, एक ट्रिपल स्वयं उन स्थितियों में एक मान्य टर्म बन जाता है। नीचे +उम्मीदवार क्वेरी पैटर्न दिए गए हैं जो मूल लक्ष्यों का समर्थन करते हैं। + +#### ग्राफ पैरामीटर अर्थशास्त्र + +पिछड़ी संगतता के लिए SPARQL सम्मेलनों का पालन करना: + +- **`g` छोड़ा गया / None**: केवल डिफ़ॉल्ट ग्राफ क्वेरी करें +- **`g` = विशिष्ट IRI**: केवल उस नामित ग्राफ को क्वेरी करें +- **`g` = वाइल्डकार्ड / `*`**: सभी ग्राफों में क्वेरी करें (SPARQL के बराबर + `GRAPH ?g { ... }`) + +यह सरल क्वेरी को सरल रखता है और नामित ग्राफ क्वेरी को वैकल्पिक बनाता है। + +क्रॉस-ग्राफ क्वेरी (g=वाइल्डकार्ड) पूरी तरह से समर्थित हैं। Cassandra स्कीमा +समर्पित तालिकाओं को शामिल करता है (SPOG, POSG, OSPG) जहां g एक क्लस्टरिंग कॉलम है +विभिन्न ग्राफों में कुशल क्वेरी सक्षम करने के लिए पार्टीशन कुंजी नहीं है। + +#### टेम्पोरल क्वेरी + +**एक निश्चित तिथि के बाद खोजे गए सभी तथ्यों का पता लगाएं:** +``` +S: ? # कोई भी उद्धृत ट्रिपल +P: +O: > "2024-01-15"^^xsd:date # तिथि तुलना +``` + +**पता लगाएं कि किसी विशिष्ट तथ्य को कब सत्य माना गया था:** +``` +S: << <एलिस> <जानता है> <बॉब> >> # विषय के रूप में उद्धृत ट्रिपल +P: +O: ? # तिथि लौटाता है +``` + +**उन तथ्यों का पता लगाएं जिन्हें गलत माना गया था:** +``` +S: ? # कोई भी उद्धृत ट्रिपल +P: +O: ? # कोई भी मान (अस्तित्व) +``` + +#### उत्पत्ति क्वेरी + +**किसी विशिष्ट स्रोत द्वारा समर्थित सभी तथ्यों का पता लगाएं:** +``` +S: ? # कोई भी उद्धृत ट्रिपल +P: +O: +``` + +**पता करें कि कौन से स्रोत किसी विशिष्ट तथ्य का समर्थन करते हैं:** +``` +S: << <ड्रगए> <उपचार करता है> <बीमारीबी> >> # विषय के रूप में उद्धृत ट्रिपल +P: +O: ? # स्रोत IRI लौटाता है +``` + +#### सत्यता क्वेरी + +**उन दावों का पता लगाएं जिन्हें किसी व्यक्ति ने सत्य के रूप में चिह्नित किया था:** +``` +S: ? # कोई भी उद्धृत ट्रिपल +P: +O: +``` + +**विरोधाभासी दावों का पता लगाएं (एक ही तथ्य, अलग-अलग सत्यता):** +``` +# पहली क्वेरी: सत्य माने गए तथ्य +S: ? +P: +O: ? + +# दूसरी क्वेरी: झूठे माने गए तथ्य +S: ? +P: +O: ? + +# एप्लिकेशन तर्क: विषयों के चौराहे का पता लगाएं +``` + +**उस विश्वास स्कोर का पता लगाएं जो थ्रेसहोल्ड से नीचे है:** +``` +S: ? # कोई भी उद्धृत ट्रिपल +P: +O: < 0.5 # संख्यात्मक तुलना +``` + +### आर्किटेक्चर + +कई घटकों में महत्वपूर्ण परिवर्तन आवश्यक हैं: + +#### यह भंडार (trustgraph) + +- **स्कीमा प्रिमिटिव** (`trustgraph-base/trustgraph/schema/core/primitives.py`) + - वैल्यू → टर्म का नाम बदलें + - नए टर्म संरचना में प्रकार विभेदक + - ग्राफ संदर्भ के लिए ट्रिपल में `g` +- **नाम बदलें**: `Value` क्लास का नाम बदलकर `Term` कर दिया जाएगा। यह + ~78 फ़ाइलों को कोडबेस में प्रभावित करता है। नामकरण एक मजबूर करने वाला कारक के रूप में कार्य करता है: + `Value` का उपयोग करने वाला कोई भी कोड तुरंत पहचानने योग्य है और इसे 2.0 + संगतता के लिए समीक्षा/अपडेट करने की आवश्यकता है। + +सुरक्षा विचार +नामित ग्राफ एक सुरक्षा सुविधा नहीं हैं। उपयोगकर्ता और संग्रह सुरक्षा सीमाएँ हैं। +नामित ग्राफ डेटा संगठन और पुन:पुनर्बलन समर्थन के लिए पूरी तरह से हैं। + +प्रदर्शन विचार +- उद्धृत ट्रिपल नेस्टिंग गहराई जोड़ते हैं - यह क्वेरी प्रदर्शन को प्रभावित कर सकता है +- कुशल ग्राफ-स्कोप वाली क्वेरी के लिए नामित ग्राफ इंडेक्सिंग रणनीतियाँ आवश्यक हैं +- क्वाड स्टोरेज को कुशलतापूर्वक समायोजित करने के लिए Cassandra स्कीमा डिज़ाइन + आवश्यक होगा। + +वेक्टर स्टोर सीमा +वेक्टर स्टोर हमेशा केवल IRIs को संदर्भित करते हैं: +- कभी भी किनारे (उद्धृत ट्रिपल) +- कभी भी शाब्दिक मान +- कभी भी रिक्त नोड +यह वेक्टर स्टोर को सरल रखता है - यह नामित संस्थाओं की सिमेंटिक समानता को संभालता है। +ग्राफ संरचना, पुन:पुनर्बलन और मेटाडेटा संबंध को संभालता है। उद्धृत ट्रिपल और +नामित ग्राफ वेक्टर संचालन को जटिल नहीं बनाते हैं। + +परीक्षण रणनीति +मौजूदा परीक्षण रणनीति का उपयोग करें। चूंकि यह एक ब्रेकिंग रिलीज़ है, इसलिए नए +संरचनाओं का परीक्षण करने के लिए एंड-टू-एंड परीक्षण सूट पर ध्यान केंद्रित करें ताकि यह सत्यापित किया जा सके कि +वे सभी घटकों में सही ढंग से काम करते हैं। + +प्रवासन योजना +- 2.0 एक ब्रेकिंग रिलीज़ है; कोई पिछड़ा संगतता की आवश्यकता नहीं है +- मौजूदा डेटा को नए स्कीमा में माइग्रेट करने की आवश्यकता हो सकती है (अंतिम डिज़ाइन के आधार पर TBD) +- मौजूदा ट्रिपल को बदलने के लिए माइग्रेशन टूल पर विचार करें + +खुले प्रश्न +- **रिक्त नोड**: सीमित समर्थन की पुष्टि की गई है। एक स्कोलेम रणनीति पर निर्णय लेने + हो सकता है (लोडिंग पर IRI उत्पन्न करें, या रिक्त नोड ID को संरक्षित करें)। +- **क्वेरी सिंटैक्स**: उद्धृत ट्रिपल को क्वेरी में निर्दिष्ट करने के लिए ठोस सिंटैक्स क्या है? + क्वेरी API को परिभाषित करने की आवश्यकता है। +- ~~**विधेय शब्दावली**~~: हल किया गया। किसी भी वैध RDF विधेय की अनुमति है, + जिसमें कस्टम उपयोगकर्ता-परिभाषित भी शामिल हैं। RDF वैधता के बारे में बहुत कम धारणाएं। + रणनीति: जब तक बिल्कुल आवश्यक न हो, कुछ भी लॉक न करें। +- ~~**वेक्टर स्टोर प्रभाव**~~: हल किया गया। वेक्टर स्टोर हमेशा केवल IRIs को संदर्भित करते हैं + - कभी भी किनारे, शाब्दिक, या रिक्त नोड। उद्धृत ट्रिपल और + पुन:पुनर्बलन वेक्टर स्टोर को प्रभावित नहीं करते हैं। +- ~~**नामित ग्राफ अर्थशास्त्र**~~: हल किया गया। क्वेरी डिफ़ॉल्ट में डिफ़ॉल्ट ग्राफ + (पिछड़ी संगत SPARQL व्यवहार)। नामित ग्राफ या सभी ग्राफों को क्वेरी करने के लिए + एक स्पष्ट ग्राफ पैरामीटर की आवश्यकता होती है। + +संदर्भ +- [RDF 1.2 अवधारणाएँ](https://www.w3.org/TR/rdf12-concepts/) +- [RDF-स्टार और SPARQL-स्टार](https://w3c.github.io/rdf-star/) +- [RDF डेटासेट](https://www.w3.org/TR/rdf11-concepts/#section-dataset) \ No newline at end of file diff --git a/docs/tech-specs/graph-contexts.ru.md b/docs/tech-specs/graph-contexts.ru.md new file mode 100644 index 00000000..300a4ae1 --- /dev/null +++ b/docs/tech-specs/graph-contexts.ru.md @@ -0,0 +1,407 @@ +``` +# Техническая спецификация контекстов графов + +## Обзор + +Эта спецификация описывает изменения основных примитивов графа TrustGraph для +соответствия RDF 1.2 и поддержки полной семантики набора данных RDF. Это +радикальное изменение для серии выпусков 2.x. + +### Версионирование + +- **2.0**: Ранний выпуск для тестирования. Основные функции доступны, но + возможно, еще не полностью готовы к производственному использованию. +- **2.1 / 2.2**: Промышленный выпуск. Стабильность и полнота проверены. + +Гибкость в отношении зрелости намеренна - ранние пользователи могут получить +доступ к новым возможностям, прежде чем все функции будут полностью +проверены. + +## Цели + +Основные цели этой работы - обеспечить возможность добавления метаданных к +фактам/утверждениям: + +- **Временная информация**: Связывание фактов со временными метаданными + - Когда факт считался истинным + - Когда факт стал истинным + - Когда факт был признан ложным + +- **Происхождение/Источники**: Отслеживание источников, подтверждающих факт + - "Этот факт подтверждается источником X" + - Связывание фактов с исходными документами + +- **Достоверность/Надежность**: Запись утверждений об истинности + - "Пользователь P заявил, что это было правдой" + - "Пользователь Q утверждает, что это неправда" + - Обеспечение оценки надежности и обнаружения конфликтов + +**Гипотеза**: Реификация (RDF-star / цитируемые тройки) является ключевым +механизмом для достижения этих результатов, поскольку все они требуют +создания утверждений об утверждениях. + +## Предыстория + +Чтобы выразить фразу "факт (Алиса знает Боба) был обнаружен 15 января 2024 года" +или "источник X поддерживает утверждение (Y вызывает Z)", необходимо +обращаться к ребру как к чему-то, о чем можно делать утверждения. Стандартные +тройки не поддерживают это. + +### Текущие ограничения + +Текущий класс `Value` в `trustgraph-base/trustgraph/schema/core/primitives.py` +может представлять: +- URI-узлы (`is_uri=True`) +- Литеральные значения (`is_uri=False`) + +Поле `type` существует, но не используется для представления типов данных XSD. + +## Технический дизайн + +### Функции RDF для поддержки + +#### Основные функции (связанные с целями реификации) + +Эти функции напрямую связаны с целями временной информации, происхождения и +достоверности: + +1. **Цитируемые тройки RDF 1.2 (RDF-star)** + - Ребра, указывающие на другие ребра + - Тройка может быть субъектом или объектом другой тройки + - Позволяет делать утверждения об утверждениях (реификация) + - Основной механизм для аннотирования отдельных фактов + +2. **Набор данных RDF / Именованные графы** + - Поддержка нескольких именованных графов внутри набора данных + - Каждый граф идентифицируется IRI + - Переход от троек (s, p, o) к квадам (s, p, o, g) + - Включает граф по умолчанию и ноль или более именованных графов + - IRI графа может быть субъектом в утверждениях, например: + ``` + "2024-01-15" + "high" + ``` + - Обратите внимание: Именованные графы - это отдельная функция от + реификации. Они имеют другие применения (разделение, контроль доступа, + организация набора данных) и должны рассматриваться как отдельная + возможность. + +3. **Анонимные узлы** (Ограниченная поддержка) + - Анонимные узлы без глобального URI + - Поддерживаются для совместимости при загрузке внешних данных RDF + - **Ограниченный статус**: Без гарантий стабильной идентичности после + загрузки + - Находите их с помощью запросов по подстановочным знакам (сопоставляйте по + связям, а не по ID) + - Не являются основной функцией - не полагайтесь на точную обработку + анонимных узлов + +#### Временные исправления (радикальное изменение в 2.0) + +Эти функции не связаны напрямую с целями реификации, но являются ценными +улучшениями, которые следует включить при внесении радикальных изменений: + +4. **Типы литералов** + - Правильное использование поля `type` для типов данных XSD + - Примеры: xsd:string, xsd:integer, xsd:dateTime и т.д. + - Исправляет текущее ограничение: невозможно правильно представлять даты + или целые числа + +5. **Языковые теги** + - Поддержка языковых атрибутов для строковых литералов (@en, @fr и т.д.) + - Обратите внимание: у литерала либо языковой тег, ЛИБО тип данных, но не + оба (за исключением rdf:langString) + - Важно для сценариев использования ИИ/многоязычности + +### Модели данных + +#### Термин (переименование из Value) + +Класс `Value` будет переименован в `Term`, чтобы лучше отражать терминологию +RDF. Это переименование имеет две цели: +1. Согласование наименований с концепциями RDF ( "Term" может быть IRI, + литералом, анонимным узлом или цитируемой тройкой - а не просто + "значением") +2. Вызывает проверку кода на интерфейсе радикальных изменений - любой код, + который все еще ссылается на `Value`, явно не работает и требует + обновления + +Термин может представлять: + +- **IRI/URI** - Именованный узел/ресурс +- **Анонимный узел** - Анонимный узел с локальной областью +- **Литерал** - Значение данных с одним из следующих: + - Тип данных (тип XSD) ИЛИ + - Языковой тег +- **Цитируемая тройка** - Тройка, используемая в качестве термина (RDF 1.2) + +##### Выбранный подход: Одиночный класс с дискриминатором типа + +Структура определяется требованиями сериализации - в формате передачи данных +необходим дискриминатор типа, независимо от представления на Python. +Одиночный класс с полем типа - это естественный выбор и соответствует +текущему шаблону `Value`. + +Односимвольный код типа обеспечивает компактную сериализацию: + +```python +from dataclasses import dataclass + +# Константы типа Term +IRI = "i" # IRI/URI узел +BLANK = "b" # Анонимный узел +LITERAL = "l" # Литеральное значение +TRIPLE = "t" # Цитируемая тройка (RDF 1.2) + +@dataclass +class Term: + type: str = "" # Один из: IRI, BLANK, LITERAL, TRIPLE + + # Для терминов IRI (type == IRI) + iri: str = "" + + # Для анонимных узлов (type == BLANK) + id: str = "" + + # Для литералов (type == LITERAL) + value: str = "" + datatype: str = "" # URI типа данных XSD (взаимно исключающееся с language) + language: str = "" # Языковой тег (взаимно исключающееся с datatype) + + # Для цитируемых троек (type == TRIPLE) + triple: "Triple | None" = None +``` + +Примеры использования: + +```python +# Термин IRI +node = Term(type=IRI, iri="http://example.org/Alice") + +# Литерал с типом данных +age = Term(type=LITERAL, value="42", datatype="xsd:integer") + +# Литерал с языковым тегом +label = Term(type=LITERAL, value="Hello", language="en") + +# Анонимный узел +anon = Term(type=BLANK, id="_:b1") + +# Цитируемая тройка (утверждение об утверждении) +inner = Triple( + s=Term(type=IRI, iri="http://example.org/Alice"), + p=Term(type=IRI, iri="http://example.org/knows"), + o=Term(type=IRI, iri="http://example.org/Bob"), +) +reified = Term(type=TRIPLE, triple=inner) +``` + +##### Рассмотренные альтернативы + +**Вариант B: Объединение специализированных классов** (`Term = IRI | BlankNode | Literal | QuotedTriple`) +- Отклонено: Сериализация все равно потребует дискриминатора типа, что + увеличивает сложность + +**Вариант C: Базовый класс с подклассами** +- Отклонено: Та же проблема с сериализацией, а также особенности + наследования dataclass + +#### Тройка / Квад + +Класс `Triple` получает необязательное поле графа, чтобы стать квадом: + +```python +@dataclass +class Triple: + s: Term | None = None # Subject + p: Term | None = None # Predicate + o: Term | None = None # Object + g: str | None = None # Имя графа (IRI), None = граф по умолчанию +``` + +Решения в дизайне: +- **Имя поля**: `g` для согласованности с `s`, `p`, `o` +- **Необязательно**: `None` означает граф по умолчанию (неименованный) +- **Тип**: Обычная строка (IRI) вместо Term + - Имена графов всегда являются IRI + - Анонимные узлы в качестве имен графов не допускаются (слишком + путано) + - Нет необходимости в полной машинерии Term + +Обратите внимание: Имя класса остается `Triple`, даже если технически это +квад. Это позволяет избежать изменений и "тройка" по-прежнему является +общепринятым термином. Контекст графа является метаданными о том, где +находится тройка. + +### Шаблоны запросов + +Текущий движок запросов принимает комбинации терминов S, P, O. С цитируемыми +тройками сама тройка может быть допустимым термином в этих позициях. Ниже +приведены примеры шаблонов запросов, поддерживающих исходные цели. + +#### Семантика параметров графа + +В соответствии с соглашениями SPARQL для обратной совместимости: + +- **`g` опущено / None**: Запрос только к графу по умолчанию +- **`g` = конкретный IRI**: Запрос только к этому именованному графу +- **`g` = подстановочный знак / `*`**: Запрос по всем графам (эквивалентно + SPARQL `GRAPH ?g { ... }`) + +Это позволяет выполнять простые запросы простыми и делает запросы именованных +графов опциональными. + +Запросы между графами (g=подстановочный знак) полностью поддерживаются. +Схема Cassandra включает специализированные таблицы (SPOG, POSG, OSPG), где g +является столбцом кластеризации, а не ключом раздела, что обеспечивает +эффективные запросы по всем графам. + +#### Временные запросы + +**Найти все факты, обнаруженные после определенной даты:** +``` +S: ? # любая цитируемая тройка +P: +O: > "2024-01-15"^^xsd:date # сравнение даты +``` + +**Найти, когда определенный факт считался истинным:** +``` +S: << >> # цитируемая тройка как субъект +P: +O: ? # возвращает дату +``` + +**Найти факты, которые были признаны ложными:** +``` +S: ? # любая цитируемая тройка +P: +O: ? # имеет любое значение (существует) +``` + +#### Запросы происхождения + +**Найти все факты, подтвержденные определенным источником:** +``` +S: ? # любая цитируемая тройка +P: +O: +``` + +**Найти, какие источники подтверждают определенный факт:** +``` +S: << >> # цитируемая тройка как субъект +P: +O: ? # возвращает IRI источника +``` + +#### Запросы достоверности + +**Найти утверждения, которые пользователь отметил как истинные:** +``` +S: ? # любая цитируемая тройка +P: +O: +``` + +**Найти конфликтующие утверждения (один и тот же факт, разная достоверность):** +``` +# Первый запрос: факты, отмеченные как истинные +S: ? +P: +O: ? + +# Второй запрос: факты, отмеченные как ложные +S: ? +P: +O: ? + +# Логика приложения: найти пересечение субъектов +``` + +**Найти факты со значением надежности ниже определенного значения:** +- **Vector store impact** +``` +S: ? +P: +O: +``` + +### Граница хранилища векторов + +Хранилища векторов всегда ссылаются только на IRI: +- Никогда на ребра (цитируемые тройки) +- Никогда на литеральные значения +- Никогда на анонимные узлы + +Это упрощает хранилище векторов - оно обрабатывает семантическое сходство +именованных сущностей. Структура графа обрабатывает отношения, +реификацию и метаданные. Цитируемые тройки и именованные графы не +усложняют операции с векторами. + +## Соображения безопасности + +Именованные графы не являются функцией безопасности. Пользователи и +коллекции остаются границами безопасности. Именованные графы предназначены +исключительно для организации данных и поддержки реификации. + +## Соображения производительности + +- Цитируемые тройки добавляют глубину вложенности - могут повлиять на + производительность запросов +- Необходимы стратегии индексирования именованных графов для эффективных + запросов, охватывающих графы +- Проект схемы Cassandra должен учитывать эффективное хранение квадов. + +### Vector store boundary + +Vector stores always reference IRIs only: +- Never edges (quoted triples) +- Never literal values +- Never blank nodes + +This keeps the vector store simple - it handles semantic similarity of named +entities. The graph structure handles relationships, reification, and metadata. +Quoted triples and named graphs don't complicate vector operations. + +## Стратегия тестирования + +Используйте существующую стратегию тестирования. Поскольку это радикальное +изменение, особое внимание уделяется комплексному набору тестов для +проверки правильности работы новых структур во всех компонентах. + +## План миграции + +- 2.0 - это радикальное изменение; обратная совместимость не требуется +- Существующие данные могут потребовать миграции на новую схему (будет + определено на основе окончательного проекта) +- Рассмотрите возможность использования инструментов миграции для преобразования + существующих троек + +## Открытые вопросы + +- **Анонимные узлы**: Подтверждена ограниченная поддержка. Возможно, потребуется + определить стратегию сколемизации (генерировать IRI при загрузке или + сохранять идентификаторы анонимных узлов). +- **Синтаксис запросов**: Какой конкретный синтаксис используется для + указания цитируемых троек в запросах? Необходимо определить API запросов. +- ~~**Словарь предикатов**~~: Решено. Допускаются любые допустимые + предикаты RDF, включая пользовательские. Минимальные предположения о + валидности RDF. Очень мало жестко заданных значений (например, + `rdfs:label` используется в некоторых местах). Стратегия: избегать + фиксирования чего-либо, если это абсолютно необходимо. +- ~~**Влияние на хранилище векторов**~~: Решено. Хранилища векторов + всегда указывают только на IRI - никогда на ребра, литеральные значения или + анонимные узлы. Цитируемые тройки и реификация не влияют на хранилище + векторов. +- ~~**Семантика именованных графов**~~: Решено. Запросы по умолчанию + выполняются к графу по умолчанию (соответствует поведению SPARQL, + обратная совместимость). Требуется явный параметр графа для запросов к + именованным графам или ко всем графам. + +## Ссылки + +- [Концепции RDF 1.2](https://www.w3.org/TR/rdf12-concepts/) +- [RDF-star и SPARQL-star](https://w3c.github.io/rdf-star/) +- [Набор данных RDF](https://www.w3.org/TR/rdf11-concepts/#section-dataset) +``` \ No newline at end of file diff --git a/docs/tech-specs/graph-contexts.sw.md b/docs/tech-specs/graph-contexts.sw.md new file mode 100644 index 00000000..e23dea54 --- /dev/null +++ b/docs/tech-specs/graph-contexts.sw.md @@ -0,0 +1,351 @@ +# Tahadhari za Kiufundi za Mazingira ya Picha (Graph Contexts) + +## Muhtasari + +Maelezo haya yanataja mabadiliko kwenye vitu vya msingi (primitives) vya TrustGraph ili +kuendana na RDF 1.2 na kusaidia maana kamili ya RDF Dataset. Hii ni +mabadiliko ambayo yanaweza kusababisha utosoni (breaking change) kwa toleo la 2.x. + +### Matoleo + +- **2.0**: Toleo la kwanza kwa watumiaji. Vitu muhimu vipo, lakini vinaweza + kusiletelewa kikamilifu kwa matumizi ya uzalishaji. +- **2.1 / 2.2**: Toleo la uzalishaji. Uthabiti na ukamilifu umehakikishwa. + +Uhusika wa uthabiti ni wa kujua - watumiaji wa kwanza wanaweza kupata +uwezo mpya kabla ya sifa zote kuwa zimekamilishwa. + +## Lengo + +Lengo kuu la kazi hii ni kuruhusu metadata kuhusu ukweli/taarifa: + +- **Habari za muda (Temporal information)**: Kuunganisha ukweli na metadata ya wakati + - Wakati ambapo ukweli ulikuwa unaaminika kuwa ni kweli + - Wakati ambapo ukweli ulipoanza kuwa kweli + - Wakati ambapo ukweli ulipoonekana kuwa bandia + +- **Chanzo/Asili (Provenance/Sources)**: Kufuatilia vyanzo ambavyo vinaunga mkono ukweli + - "Ukweli huu ulikuwa unaungwa mkono na chanzo X" + - Kuunganisha ukweli na hati zao za asili + +- **Ukweli/Amani (Veracity/Trust)**: Kurekodi maelezo kuhusu ukweli + - "Mtu P amesema kwamba hii ni kweli" + - "Mtu Q anadai kwamba hii ni bandia" + - Kuruhusu upimaji wa uaminifu na ugunduzi wa migogoro + +**Nadharia**: Ufufunzaji (reification) (RDF-star / triples zilizotiwa nukuu) ni +mfumo muhimu wa kufanikisha matokeo haya, kwani yote yanahitaji kufanya +maelezo kuhusu maelezo. + +## Msingi + +Ili kueleza "ukweli kwamba (Alice anajua Bob) uligunduliwa tarehe 2024-01-15" au +"chanzo X kinaunga mkono dai kwamba (Y husababisha Z)", unahitaji +kurejelea ukingo kama kitu ambacho unaweza kufanya maelezo. Triples +za kawaida hazisaidii hii. + +### Vikwazo vya Sasa + +Darasa la `Value` linalopo `trustgraph-base/trustgraph/schema/core/primitives.py` +linaweza kuwakilisha: +- Nodi za URI (`is_uri=True`) +- Maadili ya kawaida (`is_uri=False`) + +Nguvu ya `type` ipo lakini haitumiki kuwakilisha aina za XSD. + +## Muundo wa Kiufundi + +### Sifa za RDF za Kusaidiwa + +#### Sifa za Msingi (Zilizohusiana na Lengo la Ufufunzaji) + +Sifa hizi zinahusiana moja kwa moja na malengo ya muda, chanzo, na ukweli: + +1. **Triples Zilizotiwa Nukuu za RDF 1.2 (RDF-star)** + - Ukingo ambao unaelekea kwenye ukingo mwingine + - Triple inaweza kuonekana kama mada au kitu cha Triple nyingine + - Inaruhusu maelezo kuhusu maelezo (ufufunzaji) + - Mfumo muhimu wa kuongeza maelezo kwa ukweli binafsi + +2. **RDF Dataset / Picha Zilizojulikana (Named Graphs)** + - Usaidizi wa picha nyingi zilizojulikana ndani ya dataset + - Kila picha huainishwa na IRI + - Mabadiliko kutoka kwa triples (s, p, o) hadi quads (s, p, o, g) + - Inajumuisha picha ya chaguo-msingi pamoja na picha za majina + - IRI ya picha inaweza kuwa mada katika maelezo, kwa mfano: + ``` + "2024-01-15" + "high" + ``` + - Kumbuka: Picha zilizojulikana ni kipengele tofauti kutoka kwa ufufunzaji. + Zina matumizi mengine yakiwa nje ya kuongeza maelezo (kugawanya, udhibiti + wa ufikiaji, shirika la dataset) na zinapaswa kuchukuliwa kama + uwezo tofauti. + +3. **Nodi Tupu (Limited Support)** + - Nodi bila URI ya kimataifa + - Inasaidiwa kwa utangamano wakati wa kupakua data ya RDF ya nje + - **Hali mdogo**: Hakuna ahadi kuhusu utambulisho wa imara baada ya kupakia + - Zipate kupitia maswali ya wildcard (pangilia kwa muunganisho, sio kwa ID) + - Sio kipengele cha kwanza - usitegemee usimamizi sahihi wa nodi tupu + +#### Marekebisho ya Nafasi (2.0 Breaking Change) + +Sifa hizi hazihusiani moja kwa moja na malengo ya ufufunzaji lakini ni +mafanikio muhimu ya kuingiza wakati wa kufanya mabadiliko ambayo yanaweza +kusababisha utosoni: + +4. **Aina za Literal** + - Tumia vizuri nguvu ya `type` kwa aina za XSD + - Mifano: xsd:string, xsd:integer, xsd:dateTime, n.k. + - Huondoa kikwazo cha sasa: haiwezi kuwakilisha tarehe au nambari + kwa usahihi + +5. **Lebo za Lugha** + - Usaidizi wa sifa za lugha kwenye maadili ya kawaida (@en, @fr, n.k.) + - Kumbuka: Literal inaweza kuwa na lebo ya lugha AU aina, sio zote + (isipokuwa rdf:langString) + - Muhimu kwa matumizi ya AI/mbalimbali za lugha + +### Miundo ya Data + +#### Nguvu (kutoka Value) + +Darasa la `Value` litabadilishwa na `Term` ili kuakisi vizuri dhana za RDF. +Mabadiliko haya yafanywa kwa sababu mbili: +1. Inaakisi majina na dhana za RDF (nguvu inaweza kuwa IRI, literal, + nodi tupu, au triple iliyotiwa nukuu - sio tu "maadili") +2. Inalazimisha ukaguzi wa msimbo kwenye interface ya mabadiliko ambayo + yanaweza kusababisha utosoni - msimbo wowote unaoendelea kurejelea `Value` + unaonyeshwa kuwa umevunjika na unahitaji kusasishwa. + +Nguvu inaweza kuwakilisha: + +- **IRI/URI** - Nodi/rasilimali iliyojulikana +- **Nodi Tupu** - Nodi isiyo na jina yenye upeo wa ndani +- **Literal** - Maadili ya data ambayo ina: + - Aina ya data (aina ya XSD), AU + - Lebo ya lugha +- **Triple Iliyotiwa Nukuu** - Triple inayotumika kama nguvu (RDF 1.2) + +##### Mbinu Iliyo Chaguliwa: Darasa Moja na Kichunguzi Aina + +Mahitaji ya utayarishaji yanaendesha muundo - kichunguzi aina inahitajika +katika muundo wa waya bila kujali uwakilishi wa Python. Darasa moja na +aina ni inayofaa na inaakibiana na mtindo wa `Value` wa sasa. + +Msimbo wa aina ya herufi moja hutoa utayarishaji kompakt: + +```python +from dataclasses import dataclass + +# Mara ya aina ya Nguvu +IRI = "i" # Nodi ya IRI/URI +BLANK = "b" # Nodi tupu +LITERAL = "l" # Maadili +TRIPLE = "t" # Triple iliyotiwa nukuu (RDF 1.2) + +@dataclass +class Term: + type: str = "" # Moja ya: IRI, BLANK, LITERAL, TRIPLE + + # Kwa masharti ya IRI (aina == IRI) + iri: str = "" + + # Kwa nodi tupu (aina == BLANK) + id: str = "" + + # Kwa maadili (aina == LITERAL) + value: str = "" + datatype: str = "" # URI ya aina ya XSD (inatenganishwa) + language: str = "" # Lebo ya lugha (inatenganishwa) + + # Kwa triples zilizotiwa nukuu (aina == TRIPLE) + triple: "Triple | None" = None +``` + +Mifano ya matumizi: + +```python +# Nguvu ya IRI +node = Term(type=IRI, iri="http://example.org/Alice") + +# Maadili na aina +age = Term(type=LITERAL, value="42", datatype="xsd:integer") + +# Maadili na lebo ya lugha +label = Term(type=LITERAL, value="Hello", language="en") + +# Nodi tupu +anon = Term(type=BLANK, id="_:b1") + +# Triple iliyotiwa nukuu (taarifa kuhusu taarifa) +inner = Triple( + s=Term(type=IRI, iri="http://example.org/Alice"), + p=Term(type=IRI, iri="http://example.org/knows"), + o=Term(type=IRI, iri="http://example.org/Bob"), +) +reified = Term(type=TRIPLE, triple=inner) +``` + +##### Mbinu Zingine Zilizozingatiwa + +**Njia B: Muungano wa madarasa maalum** (`Term = IRI | BlankNode | Literal | QuotedTriple`) +- Ilikataliwa: Utayarishaji bado unahitaji kichunguzi aina, na kuongeza + ugumu. + +**Njia C: Darasa la msingi na madarasa ya ndoto** +- Ilikataliwa: Tatizo lile lile la utayarishaji, pamoja na utata wa + urithi wa dataclass + +#### Triple / Quad + +Darasa la `Triple` hupata nguvu ya hiari kuwa quad: + +```python +@dataclass +class Triple: + s: Term | None = None # Mada + p: Term | None = None # Kieleuzo + o: Term | None = None # Kitu + g: str | None = None # Jina la picha (IRI), None = picha ya + # chaguo-msingi +``` + +Maamuzi ya muundo: +- **Jina la nguvu**: `g` kwa utangamano na `s`, `p`, `o` +- **Hiari**: `None` inamaanisha picha ya chaguo-msingi (isiyo na jina) +- **Aina**: Kamba (IRI) badala ya Nguvu + - Majina ya picha daima ni IRIs + - Nodi tupu kama majina ya picha zilikataliwa (zinaweza kusababisha + uchanganyifu) + - Hakuna haja ya utaratibu kamili wa Nguvu + +Kumbuka: Jina la darasa linaendelea kuwa `Triple` licha ya kuwa quad sasa. +Hii inazuia mabadiliko na "triple" bado ni terminolojia ya kawaida. +Mazingira ya picha ni metadata kuhusu mahali ambapo triple inakaa. + +### Mfano wa Maswali Yanayowezekana + +Msimu wa maswali unaokubaliwa hivi sasa unachanganya masharti ya S, P, O. +Katika quoted triples, triple yenyewe inakuwa nguvu halali katika +maeneo hayo. Hapa chini kuna mifano ya maswali yanayodumisha malengo +yaliyoelezwa. + +#### Semantika ya Paramu ya Picha + +Kufuata makubaliano ya SPARQL kwa utangamano wa kurudi nyuma: + +- **`g` imepunguzwa / None**: Huuliza picha ya chaguo-msingi pekee +- **`g` = IRI maalum**: Huuliza picha hiyo maalum pekee +- **`g` = wildcard / `*`**: Huuliza katika picha zote (inalingana na + SPARQL `GRAPH ?g { ... }`) + +Hii inaendelea na maswali rahisi rahisi na inafanya maswali ya picha +kuwa ya hiari. + +Maswali ya picha (g=wildcard) yanasaidiwa kikamilifu. Cassandra schema +inajumuisha jedwali maalum (SPOG, POSG, OSPG) ambapo g ni nguzo ya +kugandana badala ya nguzo ya sehemu, na inaruhusu maswali ya ufanisi +katika picha zote. + +#### Maswali ya Muda + +**Kutafuta ukweli wote ambao uligunduliwa baada ya tarehe fulani:** +``` +S: ? # triple yoyote iliyotiwa nukuu +P: +O: > "2024-01-15"^^xsd:date +G: null +``` +**Kumbuka:** `^^xsd:date` inahitajika ili kuonyesha kuwa `2024-01-15` ni +tarehe, si kamba. + +**Kumbuka:** Huwezi kuuliza "tafuta triples ambapo kieleuzo cha mada ya +triple iliyotiwa nukuu ni X" + +#### Maswala ya Chanzo/Asili + +```python +# Tafuta ukweli ambao umeungwa mkono na chanzo X +# Tafuta taarifa ambapo chanzo ni X +# Tafuta masharti ambapo chanzo ni X +``` + +#### Maswala ya Ukweli/Amani + +```python +# Tafuta maelezo ambayo yamesemwa kuwa ni kweli +# Tafuta masharti ambapo ukweli ni kweli +# Tafuta maelezo ambayo yamesemwa kuwa ni kweli +``` + +Vitu vyote vyote vya RDF vinaruhusiwa, ikiwa ni pamoja na maneno ya +mtumiaji. Mkakati: epuka kuweka kitu chochote kilichofungwa isipokuwa +linapohitajika. + +## Masuala ya Usalama + +Picha hazina kipengele cha usalama. Watumiaji na makusudi ndio mipaka +ya usalama. Picha ni tu kwa shirika la data na usaidizi wa ufufunzaji. + +## Masuala ya Utendaji + +- Triples zilizotiwa nukuu zinaongeza kina cha kuziba - zinaweza kuathiri + utendaji wa maswali +- Mikakati ya ufuataji wa picha inahitajika kwa maswali ya picha +- Muundo wa schema ya Cassandra utahitaji kuweka nafasi kwa uhifadhi + wa quad kwa ufanisi + +### Kikomo cha Hifadhi ya Vector + +Hifadhi za vector daima zinaunga mkono IRIs pekee: +- Kamwe ukingo (triples zilizotiwa nukuu) +- Kamwe maadili +- Kamwe nodi tupu + +Hii inahifadhi hifadhi ya vector kuwa rahisi - inashughulikia utangamano +wa kimaana wa vitu vilivyoainishwa. Muundo wa grafu hushughulikia +mahusiano, ufufunzaji, na metadata. Triples zilizotiwa nukuu na picha +hazichanganyishi shughuli za vector. + +## Mkakati wa Majaribio + +Tumia mkakati wa sasa wa majaribio. Kwa kuwa hii ni mabadiliko ambayo +yanaweza kusababisha utosoni, zingatia sana seti ya majaribio ya mwisho +ku hakikisha kwamba miundo mipya inafanya kazi vizuri katika vipengele +vyote. + +## Mpango wa Uhamishaji + +- 2.0 ni toleo ambalo linaweza kusababisha utosoni; hakuna utangamano + wa kurudi nyuma unaohitajika +- Data iliyopo inaweza kuhitaji uhamishaji kwenye schema mpya (itaamuliwa + kulingana na muundo wa mwisho) +- Tafadhali fikiria zana za uhamishaji kwa ajili ya kubadilisha triples + zilizo zilizopo. + +## Masuala yaliyowazi + +- **Nodi tupu**: Usaidizi mdogo umeanzishwa. Inaweza kuhitaji uamuzi wa + mkakati wa skolemization (kuunda IRIs wakati wa kupakua, au kudumisha + vitambulisho vya nodi tupu). +- **Mbinu ya maswali**: Mbinu halisi ya kutaja triples zilizotiwa nukuu + katika maswali ni nini? Tafadhali define API ya swali. +- ~~**Sanaa ya kieleuzo**~~: Limeelekezwa. Maneno yoyote ya RDF yanaruhusiwa, + pamoja na maneno ya mtumiaji. Vipengele vichache tu vya kufungwa (k.m., + rdfs:label inatumiwa katika baadhi ya maeneo). + Mkakati: epuka kufunga kitu chochote isipokuwa kinapohitajika. +- ~~**Athari ya hifadhi ya vector**~~: Limeelekezwa. Hifadhi za vector + daima zinarejelea IRIs pekee - kamwe ukingo, maadili, au nodi tupu. + Triples zilizotiwa nukuu na ufufunzaji hazisababishi hifadhi ya vector. +- ~~**Semantika ya picha**~~: Limeelekezwa. Maswali huanguka chaguo-msingi + kwenye picha ya chaguo-msingi (inalingana na tabia ya SPARQL, inafaa + kurudi nyuma). Paramu halisi ya picha inahitajika kuuliza picha + zilizoainishwa au picha zote. + +## Marejeo + +- [Mawazo ya RDF 1.2](https://www.w3.org/TR/rdf12-concepts/) +- [RDF-star na SPARQL-star](https://w3c.github.io/rdf-star/) +- [RDF Dataset](https://www.w3.org/TR/rdf11-concepts/#section-dataset) \ No newline at end of file diff --git a/docs/tech-specs/graph-contexts.zh-cn.md b/docs/tech-specs/graph-contexts.zh-cn.md new file mode 100644 index 00000000..a762b30b --- /dev/null +++ b/docs/tech-specs/graph-contexts.zh-cn.md @@ -0,0 +1,417 @@ +# Graph Contexts 技术规范 + +## 概述 + +本规范描述了 TrustGraph 核心图结构体的变更,以符合 RDF 1.2 标准并支持完整的 RDF 数据集语义。 这对 2.x 版本系列是一个破坏性变更。 + +### 版本控制 + +- **2.0**: 早期采用版本。核心功能可用,可能尚未完全达到生产级别。 +- **2.1 / 2.2**: 生产版本。稳定性和完整性已验证。 + +关于成熟度的灵活性是故意的 - 早期采用者可以访问新的功能,而所有功能尚未经过生产环境的验证。 + +## 目标 + +本次工作的首要目标是启用关于事实/声明的元数据: + +- **时间信息**: 将事实与时间元数据关联 + - 确定一个事实何时被认为是正确的。 + - 确定一个事实何时开始成立。 + - 确定一个事实何时被发现是错误的。 + +- **来源/溯源**: 跟踪哪些来源支持一个事实 + - “这个事实由来源 X 支持”。 + - 将事实链接回其原始文档。 + +- **真实性/信任度**: 记录对真实性的断言 + - “Person P 声明这是真的”。 + - “Person Q 声称这是假的”。 + - 启用信任评分和冲突检测。 + +**假设**: 重构(RDF-star / 引用三元组)是实现这些目标的关键机制,因为所有这些都要求对声明进行声明。 + +## 背景 + +为了表达“事实(Alice 知道 Bob)于 2024-01-15 被发现”或“来源 X 支持(Y 导致 Z)的声明”,您需要引用一个边作为可以进行声明的对象。 标准的三元组不支持这种情况。 + +### 当前限制 + +`trustgraph-base/trustgraph/schema/core/primitives.py` 中的当前 `Value` 类可以表示: +- URI 节点 (`is_uri=True`) +- 原始值 (`is_uri=False`) + +`type` 字段存在,但未用于表示 XSD 数据类型。 + +## 技术设计 + +### 需要支持的 RDF 功能 + +#### 核心功能(与重构目标相关) + +这些功能与时间、溯源和真实性目标直接相关: + +1. **RDF 1.2 引用三元组 (RDF-star)** + - 指向其他边的边。 + - 三元组可以作为另一个三元组的主语或宾语。 + - 启用关于声明的声明(重构)。 + - 注释单个事实的核心机制。 + +2. **RDF 数据集 / 命名图** + - 支持数据集中的多个命名图。 + - 每个图由 IRI 标识。 + - 从三元组 (s, p, o) 转换为四元组 (s, p, o, g)。 + - 包含一个默认图以及零个或多个命名图。 + - 图 IRI 可以是语句的主语,例如: + ``` + "2024-01-15" + "high" + ``` + - 注意:命名图是一个与重构分离的功能。 它们除了语句注释之外还有其他用途(分区、访问控制、数据集组织),并且应该被视为一种不同的能力。 + +3. **匿名节点** (有限支持) + - 没有全局 URI 的匿名节点。 + - 用于兼容性,以便加载外部 RDF 数据。 + - **有限状态**: 对加载后身份的稳定性没有保证。 + - 通过通配符查询找到它们(通过连接匹配,而不是通过 ID)。 + - 不是首选功能 - 不要依赖于精确的匿名节点处理。 + +#### 机会性修复 (2.0 破坏性变更) + +这些功能与重构目标没有直接关系,但包含在破坏性变更中是有价值的改进: + +4. **原始数据类型** + - 正确使用 `type` 字段表示 XSD 数据类型。 + - 示例:xsd:string, xsd:integer, xsd:dateTime 等。 + - 修复当前限制:无法正确表示日期或整数。 + +5. **语言标签** + - 支持字符串原始值上的语言属性 (@en, @fr 等)。 + - 注意:一个原始值要么有一个语言标签,要么有一个数据类型,两者不能同时存在(除了 rdf:langString)。 + - 对于 AI/多语言用例非常重要。 + +### 数据模型 + +#### Term (重命名自 Value) + +`Value` 类将被重命名为 `Term`,以更好地反映 RDF 术语。 +此重命名有两个目的: +1. 与 RDF 概念对齐命名(“Term”可以是 IRI、原始值、匿名节点或引用三元组,而不仅仅是“值”)。 +2. 在破坏性变更接口强制代码审查 - 任何仍然引用 `Value` 的代码都会立即显示为已损坏,并且需要更新。 + +一个 Term 可以表示: + +- **IRI/URI** - 命名节点/资源。 +- **匿名节点** - 具有本地作用域的匿名节点。 +- **原始值** - 具有以下之一的数据值: + - 数据类型 (XSD 类型),或 + - 语言标签。 +- **引用三元组** - 用作项的三元组 (RDF 1.2)。 + +##### 选定的方法:具有类型区分器的单个类 + +序列化要求驱动结构 - 无论 Python 表示形式如何,都需要类型区分器。 具有类型字段的单个类是最佳选择,并且与当前的 `Value` 模式一致。 + +单字符类型代码提供紧凑的序列化: + +```python +from dataclasses import dataclass + +# Term 类型常量 +IRI = "i" # IRI/URI 节点 +BLANK = "b" # 匿名节点 +LITERAL = "l" # 原始值 +TRIPLE = "t" # 引用三元组 (RDF-star) + +@dataclass +class Term: + type: str = "" # 之一: IRI, BLANK, LITERAL, TRIPLE + + # 对于 IRI 项 (type == IRI) + iri: str = "" + + # 对于匿名节点 (type == BLANK) + id: str = "" + + # 对于原始值 (type == LITERAL) + value: str = "" + datatype: str = "" # XSD 数据类型 URI (与语言互斥) + language: str = "" # 语言标签 (与数据类型互斥) + + # 对于引用三元组 (type == TRIPLE) + triple: "Triple | None" = None +``` + +用法示例: + +```python +# IRI 项 +node = Term(type=IRI, iri="http://example.org/Alice") + +# 带数据类型的原始值 +age = Term(type=LITERAL, value="42", datatype="xsd:integer") + +# 带语言标签的原始值 +label = Term(type=LITERAL, value="Hello", language="en") + +# 匿名节点 +anon = Term(type=BLANK, id="_:b1") + +# 引用三元组 (关于声明的声明) +inner = Triple( + s=Term(type=IRI, iri="http://example.org/Alice"), + p=Term(type=IRI, iri="http://example.org/knows"), + o=Term(type=IRI, iri="http://example.org/Bob"), +) +reified = Term(type=TRIPLE, triple=inner) +``` + +##### 考虑的替代方案 + +**选项 B:专用类的联合** (`Term = IRI | BlankNode | Literal | QuotedTriple`) +- 拒绝:仍然需要类型区分器进行序列化,增加了复杂性。 + +**选项 C:具有子类的基本类** +- 拒绝:与序列化问题相同,此外还有 dataclass 继承的复杂性。 + +#### Triple / Quad + +`Triple` 类获得一个可选的图字段,以成为四元组: + +```python +@dataclass +class Triple: + s: Term | None = None # 主语 + p: Term | None = None # 谓词 + o: Term | None = None # 宾语 + g: str | None = None # 图名 (IRI),None = 默认图 +``` + +设计决策: +- **字段名称**: `g` 用于与 `s`、`p`、`o` 一致。 +- **可选**: `None` 表示默认图(无命名)。 +- **类型**: 纯字符串 (IRI),而不是 Term + - 图名始终是 IRI。 + - 匿名节点作为图名被排除(过于混乱)。 + - 不需要完整的 Term 机制。 + +注意:类名保持为 `Triple`,即使它现在实际上是一个四元组。 +这避免了变更,并且术语“三元组”仍然是常见的术语。 图上下文是关于三元组存储位置的元数据。 + +### 候选查询模式 + +当前查询引擎接受 S、P、O 项的组合。 使用引用三元组时,一个三元组本身可以成为这些位置上的有效项。 以下是支持原始目标的候选查询模式。 + +#### 图参数语义 + +遵循 SPARQL 的约定以实现向后兼容: + +- **`g` 被省略 / None**: 仅查询默认图。 +- **`g` = 特定 IRI**: 仅查询该命名图。 +- **`g` = 通配符 / `*`**: 查询所有图 (相当于 SPARQL `GRAPH ?g { ... }`) + +这保持简单查询的简单性,并使命名图查询成为可选。 + +完全支持跨图查询 (g=通配符)。 Cassandra 模式包含专门的表,其中 g 是一个聚类列,而不是分区键,从而实现高效的跨所有图的查询。 + +#### 时间查询 + +**查找在特定日期之后发现的所有事实:** +``` +S: ? # 任何引用三元组 +P: +O: > "2024-01-15"^^xsd:date # 日期比较 +``` + +**查找何时认为特定事实成立:** +``` +S: << >> # 引用三元组作为主语 +P: +O: ? # 返回日期 +``` + +**查找被发现为错误的 facts:** +``` +S: ? # 任何引用三元组 +P: +O: ? # 具有任何值 (存在) +``` + +#### 溯源查询 + +**查找由特定来源支持的所有事实:** +``` +S: ? # 任何引用三元组 +P: +O: +``` + +**查找哪些来源支持特定事实:** +``` +S: << >> # 引用三元组作为主语 +P: +O: ? # 返回来源 IRI +``` + +#### 真实性查询 + +**查找 Person 声明为真的断言:** +``` +S: ? # 任何引用三元组 +P: +O: +``` + +**查找冲突的断言 (相同的 facts,不同的真实性):** +``` +# 第一个查询:声明为真的事实 +S: ? +P: +O: ? + +# 第二个查询:声明为假的 fact +S: ? +P: +O: ? + +# 应用程序逻辑:查找主语的交集 +``` + +**查找信任评分低于阈值的 facts:** +``` +S: ? # 任何引用三元组 +P: +O: < 0.5 # 数值比较 +``` + +### 架构 + +需要对多个组件进行重大更改: + +#### 此仓库 (trustgraph) + +- **模式原始数据类型** (`trustgraph-base/trustgraph/schema/core/primitives.py`) + - `Value` → `Term` 重命名。 + - 具有类型区分器的新的 `Term` 结构。 + - `Triple` 获得 `g` 字段以进行图上下文。 + +- **消息翻译器** (`trustgraph-base/trustgraph/messaging/translators/`) + - 更新以适应新的 `Term` 和 `Triple` 结构。 + - 用于新字段的序列化/反序列化。 + +- **网关组件** + - 处理新的 `Term` 和四元组结构。 + +- **知识核心** + - 支持四元组和重构的核心更改。 + +- **知识管理器** + - 模式更改会在此处传播。 + +- **存储层** + - Cassandra: 重新设计模式(参见“实施详细信息”)。 + - 其他后端:推迟到后续阶段。 + +- **命令行工具** + - 更新以适应新的数据结构。 + +- **REST API 文档** + - 更新 OpenAPI 规范。 + +#### 外部仓库 + +- **Python API** (此仓库) + - 更新客户端库以匹配新的结构。 + +- **TypeScript API** (单独仓库) + - 平行于 Python API 的更改。 + - 分离的发布协调。 + +- **Workbench** (单独仓库) + - 状态管理方面的重大更改。 + - 用于图上下文功能的 UI 更新。 + +### API + +#### REST API + +- 在 OpenAPI 规范中记录。 +- 需要更新以适应新的 `Term` 和 `Triple` 结构。 +- 可能需要新的端点来处理图上下文操作。 + +#### Python API (此仓库) + +- 客户端库更改以匹配新的原始数据类型。 +- `Term` (以前是 `Value`) 和 `Triple` 的破坏性更改。 + +#### TypeScript API (单独仓库) + +- 与 Python API 平行的更改。 +- 分离的发布协调。 + +#### Workbench (单独仓库) + +- 状态管理方面的重大更改。 +- 用于图上下文功能的 UI 更新。 + +### 实施细节 + +#### 分阶段的存储实施 + +存在多个图存储后端(Cassandra、Neo4j 等)。 +实施将分阶段进行: + +1. **第一阶段:Cassandra** + - 在完全控制的后端上验证设计,然后再承诺在所有存储系统中的实现。 + +2. **第二阶段+:其他后端** + - 在后续阶段实施 Neo4j 和其他存储系统。 + +此方法通过在所有系统上承诺实现之前,在完全受控的后端上验证设计,从而降低风险。 + +#### `Value` → `Term` 重命名 + +`Value` 类将被重命名为 `Term`。 这会影响代码库中的约 78 个文件。 +重命名充当强制函数:任何仍然使用 `Value` 的代码都将立即显示为需要审查/更新以获得 2.0 兼容性。 + +## 安全注意事项 + +命名图不是安全功能。 用户和集合仍然是安全边界。 命名图纯粹用于数据组织和重构支持。 + +## 性能注意事项 + +- 引用三元组会增加嵌套深度,这可能会影响查询性能。 +- 需要命名图索引策略以实现高效的范围查询。 +- Cassandra 模式设计需要适应四元组存储。 + +### 向量存储边界 + +向量存储始终只引用 IRI: +- 永远不要边(引用三元组)。 +- 永远不要原始值。 +- 永远不要匿名节点。 + +这使向量存储保持简单 - 它处理命名实体语义相似性。 图结构处理关系、重构和元数据。 引用三元组和命名图不会使向量操作复杂化。 + +## 测试策略 + +使用现有的测试策略。 由于这是一个破坏性版本,因此需要重点关注端到端测试套件,以验证新的结构是否在所有组件中都正确工作。 + +## 迁移计划 + +- 2.0 是一个破坏性版本;不需要向后兼容性。 +- 现有数据可能需要迁移到新的模式(基于最终设计的确定)。 +- 考虑迁移工具,用于转换现有三元组。 + +## 开放问题 + +- **匿名节点**: 确认有限支持。 可能需要决定采用 Skolem 化策略(在加载时生成 IRI,或保留匿名节点 ID)。 +- **查询语法**: 引用三元组在查询中的具体语法是什么? 需要定义查询 API。 +- **谓词词汇表**: 已解决。 允许任何有效的 RDF 谓词,包括自定义的用户定义的谓词。 尽量减少对任何事情的锁定(例如,在某些地方使用 `rdfs:label`)。 策略:除非绝对必要,否则避免锁定任何内容。 +- **向量存储影响**: 已解决。 向量存储始终仅指向 IRI - 永远不要边、原始值或匿名节点。 引用三元组和重构不会影响向量存储。 + +## 参考文献 + +- [RDF 1.2 概念](https://www.w3.org/TR/rdf12-concepts/) +- [RDF-star 和 SPARQL-star](https://w3c.github.io/rdf-star/) +- [RDF 数据集](https://www.w3.org/TR/rdf11-concepts/#section-dataset) \ No newline at end of file diff --git a/docs/tech-specs/graphrag-performance-optimization.ar.md b/docs/tech-specs/graphrag-performance-optimization.ar.md new file mode 100644 index 00000000..1857b843 --- /dev/null +++ b/docs/tech-specs/graphrag-performance-optimization.ar.md @@ -0,0 +1,270 @@ +# مواصفات فنية لتحسين أداء GraphRAG + +## نظرة عامة + +تصف هذه المواصفات تحسينات شاملة للأداء لخوارزمية GraphRAG (Graph Retrieval-Augmented Generation) في TrustGraph. تعاني التنفيذ الحالي من نقاط اختناق كبيرة في الأداء تؤثر على قابلية التوسع وأوقات الاستجابة. تعالج هذه المواصفات أربعة مجالات رئيسية للتحسين: + +1. **تحسين اجتياز الرسم البياني**: التخلص من استعلامات قاعدة البيانات المتكررة وغير الفعالة وتنفيذ استكشاف الرسم البياني المجمّع. +2. **تحسين حل التسميات**: استبدال استرداد التسميات التسلسلي بعمليات متوازية/مجمعة. +3. **تحسين استراتيجية التخزين المؤقت**: تنفيذ تخزين مؤقت ذكي مع الإخلاء حسب الأقل استخدامًا (LRU) والتحميل المسبق. +4. **تحسين الاستعلام**: إضافة تجميع النتائج وتخزين تضمينات الاستعلام لتحسين أوقات الاستجابة. + +## الأهداف + +- **تقليل حجم استعلامات قاعدة البيانات**: تحقيق تقليل بنسبة 50-80% في إجمالي استعلامات قاعدة البيانات من خلال التجميع والتخزين المؤقت. +- **تحسين أوقات الاستجابة**: استهداف سرعة بناء الرسوم البيانية الفرعية 3-5 مرات أسرع وحل التسميات 2-3 مرات أسرع. +- **تعزيز قابلية التوسع**: دعم رسوم بيانية معرفية أكبر مع إدارة أفضل للذاكرة. +- **الحفاظ على الدقة**: الحفاظ على وظائف GraphRAG الحالية وجودة النتائج. +- **تمكين التزامن**: تحسين إمكانات المعالجة المتوازية للطلبات المتزامنة المتعددة. +- **تقليل البصمة الذاكرة**: تنفيذ هياكل بيانات وإدارة ذاكرة فعالة. +- **إضافة إمكانية المراقبة**: تضمين مقاييس الأداء وقدرات المراقبة. +- **ضمان الموثوقية**: إضافة معالجة مناسبة للأخطاء وآليات المهلة. + +## الخلفية + +يظهر التنفيذ الحالي لـ GraphRAG في `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` عدة مشاكل أداء حرجة تؤثر بشدة على قابلية توسع النظام: + +### المشاكل الحالية في الأداء + +**1. اجتياز الرسم البياني غير الفعال (`follow_edges` function، الأسطر 79-127)** +- يقوم بإجراء 3 استعلامات منفصلة لقاعدة البيانات لكل كيان ولكل مستوى عمق. +- نمط الاستعلام: استعلامات تعتمد على الموضوع، تعتمد على المرجع، وتعتمد على الكائن لكل كيان. +- لا يوجد تجميع: يعالج كل استعلام كيانًا واحدًا فقط في كل مرة. +- لا يوجد اكتشاف دورة: يمكن إعادة زيارة نفس العقد عدة مرات. +- يؤدي التنفيذ المتكرر بدون تجميع إلى تعقيد أسي. +- التعقيد الزمني: O(entities × max_path_length × triple_limit³) + +**2. حل تسلسلي للتسميات (`get_labelgraph` function، الأسطر 144-171)** +- يعالج كل مكون ثلاثي (الموضوع، المرجع، الكائن) بالتسلسل. +- قد يؤدي كل استدعاء `maybe_label` إلى تشغيل استعلام قاعدة بيانات. +- لا يوجد تنفيذ متوازي أو تجميع لاستعلامات التسميات. +- يؤدي إلى ما يصل إلى 3 × مكالمات قاعدة بيانات فردية لحجم الرسوم البيانية الفرعية. + +**3. استراتيجية تخزين مؤقت بدائية (`maybe_label` function، الأسطر 62-77)** +- ذاكرة تخزين مؤقت بسيطة للقواميس بدون حدود حجم أو TTL (وقت انتهاء الصلاحية). +- لا توجد سياسة إخلاء ذاكرة التخزين المؤقت تؤدي إلى نمو غير محدود للذاكرة. +- تؤدي أخطاء ذاكرة التخزين المؤقت إلى استعلامات قاعدة بيانات فردية. +- لا يوجد تحميل مسبق أو تسخين ذكي لذاكرة التخزين المؤقت. + +**4. أنماط استعلام غير مثالية** +- استعلامات تشابه متجه الكيان غير مخزنة مؤقتًا بين الطلبات المتشابهة. +- لا يوجد تجميع للنتائج لـ أنماط الاستعلام المتكررة. +- استعلامات غير محسنة لـ الأنماط الشائعة للوصول. + +**5. مشاكل حرجة في دورة حياة الكائنات (`rag.py:96-102`)** +- **كائن GraphRag يتم إعادة إنشاؤه لكل طلب**: يتم إنشاء نسخة جديدة لكل استعلام، مما يؤدي إلى فقدان جميع فوائد ذاكرة التخزين المؤقت. +- **عمر كائن الاستعلام قصير للغاية**: يتم إنشاؤه وتدميره داخل تنفيذ استعلام واحد (الأسطر 201-207). +- **تتم إعادة تعيين ذاكرة التخزين المؤقت للتسميات لكل طلب**: يتم فقدان تسخين ذاكرة التخزين المؤقت والمعرفة المتراكمة بين الطلبات. +- **نفقات إعادة إنشاء العميل**: قد يتم إعادة إنشاء عملاء قاعدة البيانات لكل طلب. +- **لا يوجد تحسين عبر الطلبات**: لا يمكن الاستفادة من أنماط الاستعلام أو مشاركة النتائج. + +### تحليل تأثير الأداء + +السيناريو الأسوأ حاليًا لطلب نموذجي: +- **استرداد الكيان**: استعلام تشابه متجه واحد. +- **اجتياز الرسم البياني**: entities × max_path_length × 3 × triple_limit استعلامات. +- **حل التسميات**: subgraph_size × 3 استعلامات تسمية فردية. + +بالإعدادات الافتراضية (50 كيانًا، طول المسار 2، حد ثلاثي 30، حجم الرسم البياني الفرعية 150): +- **الحد الأدنى من الاستعلامات**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 استعلام لقاعدة البيانات**. +- **وقت الاستجابة**: 15-30 ثانية للرسوم البيانية متوسطة الحجم. +- **استخدام الذاكرة**: نمو غير محدود لذاكرة التخزين المؤقت بمرور الوقت. +- **فعالية ذاكرة التخزين المؤقت**: 0% - تتم إعادة تعيين ذاكرة التخزين المؤقت في كل طلب. +- **نفقات إنشاء الكائنات**: يتم إنشاء/تدمير كائنات GraphRag + Query لكل طلب. + +تعالج هذه المواصفات هذه الثغرات من خلال تنفيذ استعلامات مجمعة، وتخزين مؤقت ذكي، ومعالجة متوازية. من خلال تحسين أنماط الاستعلام والوصول إلى البيانات، يمكن لـ TrustGraph: +- دعم الرسوم البيانية المعرفية على مستوى المؤسسات مع ملايين الكيانات. +- توفير أوقات استجابة فرعية من الثانية للطلبات النموذجية. +- التعامل مع مئات الطلبات المتزامنة لـ GraphRAG. +- التوسع بكفاءة مع حجم الرسم البيانية وتعقيدها. + +## التصميم التقني + +### البنية التحتية + +يتطلب تحسين أداء GraphRAG المكونات التقنية التالية: + +#### 1. **إعادة هيكلة معمارية لدورة حياة الكائنات** + - **جعل GraphRag طويل الأمد**: نقل مثيل GraphRag إلى مستوى المعالج للاستمرار عبر الطلبات. + - **الحفاظ على ذاكرات التخزين المؤقت**: الحفاظ على ذاكرة التخزين المؤقت للتسميات، وذاكرة التخزين المؤقت للتضمينات، وذاكرة التخزين المؤقت لنتائج الاستعلام بين الطلبات. + - **تحسين كائن الاستعلام**: إعادة هيكلة الاستعلام كسياق تنفيذ خفيف الوزن، وليس حاوية بيانات. + - **استمرارية الاتصال**: الحفاظ على اتصالات عملاء قاعدة البيانات عبر الطلبات. + + الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (تم التعديل) + +#### 2. **محرك اجتياز محسّن للرسم البياني** + - استبدال `follow_edges` المتكرر ببحث عرضي تكراري. + - تنفيذ معالجة مجمعة للكيانات على كل مستوى من مستويات الاجتياز. + - إضافة اكتشاف دورة باستخدام تتبع العقد التي تمت زيارتها. + - تضمين إنهاء مبكر عند الوصول إلى الحدود. + + الوحدة: `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 دقائق) لتحقيق التوازن بين الأداء مقابل الاتساق. + - مقاييس ذاكرة التخزين المؤقت ونسبة الضبط. + - **لا يوجد تخزين مؤقت للتضمينات**: يتم بالفعل تخزين التضمينات مؤقتًا لكل استعلام. + - **لا يوجد تخزين مؤقت للنتائج**: يمنع نتائج الرسوم البيانية الفرعية القديمة من الكيانات/العلاقات المحذوفة. + + الوحدة: `trustgraph-flow/trust/graph/label_cache.py` + +#### 5. **تحسين الاستعلام والمراقبة** + - جمع مقاييس الأداء. + - تطبيق مهلة على الاستعلامات. + - إضافة دائرة كهربائية لمنع الاستخدام المفرط للموارد. + + الوحدة: `trustgraph-flow/trust/graph/query_optimizer.py` + +## اعتبارات الاتساق للذاكرة المؤقتة + +**موازنات بين بيانات قديمة**: +- **ذاكرة التخزين المؤقت للتسميات (TTL 5 دقائق)**: خطر تقديم تسميات الكيانات المحذوفة/المتجددة. +- **لا يوجد تخزين مؤقت للتضمينات**: ليس مطلوبًا - يتم تخزين التضمينات بالفعل مؤقتًا لكل استعلام. +- **لا يوجد تخزين مؤقت للنتائج**: يمنع نتائج الرسم البياني الفرعية القديمة من الكيانات/العلاقات المحذوفة. + +**استراتيجيات التخفيف**: +- **قيم TTL متحفظة**: الموازنة بين مكاسب الأداء (10-20٪) مقابل نضارة البيانات. +- **خطافات إبطال ذاكرة التخزين المؤقت**: تكامل اختياري مع أحداث تعديل الرسم البياني. +- **لوحات معلومات المراقبة**: تتبع معدلات ضرب ذاكرة التخزين المؤقت مقابل حوادث التقادم. +- **سياسات ذاكرة التخزين المؤقت القابلة للتكوين**: السماح بضبط لكل نشر بناءً على تكرار التعديل. + +**تكوين ذاكرة التخزين المؤقت الموصى به حسب معدل تعديل الرسم البياني**: +- **تعديل عالي (>100 تغيير / ساعة)**: TTL = 60 ثانية، أحجام ذاكرة تخزين مؤقت أصغر. +- **تعديل متوسط (10-100 تغيير / ساعة)**: TTL = 300 ثانية (افتراضي). +- **تعديل منخفض (<10 تغيير / ساعة)**: TTL = 600 ثانية، أحجام ذاكرة تخزين مؤقت أكبر. + +## الاعتبارات الأمنية + +**منع حقن الاستعلام**: +- التحقق من صحة جميع معرفات الكيانات ومعلمات الاستعلام. +- استخدام استعلامات مُعلمات لجميع التفاعلات مع قاعدة البيانات. +- تنفيذ حدود تعقيد الاستعلام لمنع هجمات الحرمان من الخدمة. + +**حماية الموارد**: +- فرض حدود قصوى لحجم الرسم البياني الفرعية. +- تنفيذ مهلات على الاستعلام لمنع استنفاد الموارد. +- إضافة مراقبة استخدام الذاكرة وحدود. + +**التحكم في الوصول**: +- الحفاظ على عزل المستخدم والمجموعة الحالي. +- إضافة تسجيل تدقيق للعمليات التي تؤثر على الأداء. +- تنفيذ تحديد المعدل للعمليات المكلفة. + +## اعتبارات الأداء + +### التحسينات المتوقعة في الأداء + +**تقليل الاستعلام**: +- الحالي: ~ 9000+ استعلام لطلب نموذجي. +- مُحسَّن: ~ 50-100 استعلام مجمعة (تقليل بنسبة 98٪). + +**تحسينات أوقات الاستجابة**: +- اجتياز الرسم البياني: 15-20 ثانية → 3-5 ثوانٍ (4-5 مرات أسرع). +- حل التسميات: 8-12 ثانية → 2-4 ثوانٍ (3 مرات أسرع). +- الاستعلام الإجمالي: 25-35 ثانية → 6-10 ثوانٍ (تحسين بمقدار 3-4 مرات). + +**كفاءة الذاكرة**: +- أحجام ذاكرة التخزين المؤقت المحدودة تمنع تسرب الذاكرة. +- هياكل بيانات فعالة تقلل البصمة الذاكرة بنسبة ~ 40٪. +- إدارة أفضل للذاكرة من خلال التنظيف المناسب للموارد. + +**تحسينات قابلية التوسع**: +- دعم رسوم بيانية معرفية أكبر بنسبة 3-5 مرات (محدود باحتياجات اتساق ذاكرة التخزين المؤقت). +- سعة أعلى للطلبات المتزامنة بنسبة 3-5 مرات. +- استخدام أفضل للموارد من خلال إعادة استخدام الاتصال. + +### مراقبة الأداء + +**مقاييس في الوقت الفعلي**: +- أوقات تنفيذ الاستعلام حسب نوع العملية. +- معدلات ضرب وفعالية ذاكرة التخزين المؤقت. +- استخدام مجموعة اتصالات قاعدة البيانات. +- استخدام الذاكرة وجمع البيانات المهملة. + +**قياس الأداء**: +- اختبار أداء مقابل التنفيذ الحالي. +- اختبار التحميل بأحجام بيانات وتعقيدات مختلفة. +- اختبار الضغط لحدود الموارد. +- اختبار الانحدار للتحسينات في الأداء. + +## استراتيجية الاختبار + +### اختبار الوحدة +- اختبار مكون فردي لـ الاجتياز، والتخزين المؤقت، وحل التسميات. +- محاكاة تفاعلات قاعدة البيانات لاختبار الأداء. +- اختبار الإخلاء و TTL ذاكرة التخزين المؤقت. +- سيناريوهات معالجة الأخطاء والمهلات. + +### اختبار التكامل +- اختبار GraphRAG الشامل مع التحسينات. +- اختبار تفاعل قاعدة البيانات مع بيانات حقيقية. +- اختبار التعامل مع الطلبات المتزامنة وإدارة الموارد. +- الكشف عن تسرب الذاكرة والتحقق من تنظيف الموارد. + +### اختبار الأداء +- اختبار أداء مقابل التنفيذ الحالي. +- اختبار التحميل بأحجام وتعقيدات مختلفة للرسم البياني. +- اختبار الضغط لحدود الذاكرة والاتصال. +- اختبار الانحدار للتحسينات في الأداء. + +### اختبار التوافق +- التحقق من توافق واجهة برمجة تطبيقات GraphRAG الحالية. +- الاختبار مع خلفيات قاعدة بيانات رسم بياني مختلفة. +- التحقق من دقة النتائج مقارنة بالتنفيذ الحالي. + +## خطة التنفيذ + +### النهج المباشر للتنفيذ +نظرًا للسماح بتغييرات واجهة برمجة التطبيقات، قم بتنفيذ التحسينات مباشرة دون تعقيد الترحيل: + +1. **استبدل طريقة `follow_edges`**: أعد كتابة مع اجتياز مجمّع تكراري. +2. **تحسين `get_labelgraph`**: قم بتنفيذ حل تسميات متوازي. +3. **أضف GraphRag طويل الأمد**: قم بتعديل المعالج لاستخدام نسخة مستمرة. +4. **قم بتنفيذ استراتيجية التخزين المؤقت**: أضف طبقة تخزين مؤقت إلى فئة GraphRag. + +### نطاق التغييرات +- **فئة الاستعلام**: استبدل ~50 سطرًا في `follow_edges`، وأضف ~30 سطرًا للتعامل مع التجميع. +- **فئة GraphRag**: أضف طبقة تخزين مؤقت (~40 سطرًا). +- **فئة المعالج**: قم بتعديل لاستخدام مثيل GraphRag دائم (~20 سطرًا). +- **إجمالي**: ~ 140 سطرًا من التغييرات المركزة، في الغالب داخل الفئات الحالية. + +## جدول زمني + +**الأسبوع 1: التنفيذ الأساسي** +- استبدل `follow_edges` باجتياز تكراري مجمّع. +- قم بتنفيذ حل تسميات متوازي في `get_labelgraph`. +- أضف مثيل GraphRag طويل الأمد إلى المعالج. +- قم بتنفيذ طبقة التخزين المؤقت للتسميات. + +**الأسبوع 2: الاختبار والتكامل** +- اختبارات الوحدة لمنطق الاجتياز والتخزين المؤقت الجديد. +- قياس الأداء مقابل التنفيذ الحالي. +- اختبار التكامل مع بيانات الرسم البياني الحقيقية. +- مراجعة الكود والتحسين. + +**الأسبوع 3: النشر** +- نشر التنفيذ المُحسَّن. +- مراقبة تحسينات الأداء. +- ضبط TTL ذاكرة التخزين المؤقت وأحجام الدفعات بناءً على الاستخدام الفعلي. + +## أسئلة مفتوحة + +- **تجميع الاتصال بقاعدة البيانات**: هل يجب علينا تنفيذ تجميع اتصال مخصص أم الاعتماد على تجميع عملاء قاعدة البيانات الحالي؟ +- **استمرارية ذاكرة التخزين المؤقت**: هل يجب أن تستمر ذاكرات التخزين المؤقت للتسميات والتضمينات عبر عمليات إعادة تشغيل الخدمة؟ +- **التخزين المؤقت الموزع**: بالنسبة لنشر متعدد المثيلات، هل يجب علينا تنفيذ تخزين مؤقت موزع باستخدام Redis/Memcached؟ +- **تنسيق نتيجة الاستعلام**: هل يجب علينا تحسين التمثيل الداخلي للثلاثي لتحسين كفاءة الذاكرة؟ +- **تكامل المراقبة**: ما هي المقاييس التي يجب عرضها على أنظمة المراقبة الحالية (Prometheus، إلخ)؟ + +## المراجع + +- [التنفيذ الأصلي لـ GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +- [مبادئ معمارية TrustGraph](architecture-principles.md) +- [مواصفات إدارة المجموعة](collection-management.md) \ No newline at end of file diff --git a/docs/tech-specs/graphrag-performance-optimization.es.md b/docs/tech-specs/graphrag-performance-optimization.es.md new file mode 100644 index 00000000..60b6ec04 --- /dev/null +++ b/docs/tech-specs/graphrag-performance-optimization.es.md @@ -0,0 +1,301 @@ +# Especificación Técnica de Optimización de Rendimiento de GraphRAG + +## Resumen + +Esta especificación describe optimizaciones de rendimiento integrales para el algoritmo GraphRAG (Graph Retrieval-Augmented Generation) en TrustGraph. La implementación actual sufre de cuellos de botella de rendimiento significativos que limitan la escalabilidad y los tiempos de respuesta. Esta especificación aborda cuatro áreas principales de optimización: + +1. **Optimización de la Recorrido del Grafo**: Eliminar consultas ineficientes a la base de datos y implementar exploración de grafos por lotes. +2. **Optimización de la Resolución de Etiquetas**: Reemplazar la obtención secuencial de etiquetas con operaciones paralelas/por lotes. +3. **Mejora de la Estrategia de Almacenamiento en Caché**: Implementar un almacenamiento en caché inteligente con desalojo LRU (Least Recently Used) y precarga. +4. **Optimización de Consultas**: Agregar memorización de resultados y almacenamiento en caché de incrustaciones para mejorar los tiempos de respuesta. + +## Objetivos + +- **Reducir el Volumen de Consultas a la Base de Datos**: Lograr una reducción del 50-80% en el volumen total de consultas a la base de datos a través del procesamiento por lotes y el almacenamiento en caché. +- **Mejorar los Tiempos de Respuesta**: Reducir el tiempo de construcción de subgrafos en un factor de 3 a 5 y el tiempo de resolución de etiquetas en un factor de 2 a 3. +- **Mejorar la Escalabilidad**: Compatibilizar con grafos de conocimiento más grandes con una mejor gestión de la memoria. +- **Mantener la Precisión**: Preservar la funcionalidad existente de GraphRAG y la calidad de los resultados. +- **Habilitar la Concurrencia**: Mejorar las capacidades de procesamiento paralelo para múltiples solicitudes concurrentes. +- **Reducir la Huella de Memoria**: Implementar estructuras de datos eficientes y gestión de la memoria. +- **Agregar Observabilidad**: Incluir métricas de rendimiento y capacidades de monitoreo. +- **Garantizar la Confiabilidad**: Agregar un manejo adecuado de errores y mecanismos de tiempo de espera. + +## Antecedentes + +La implementación actual de GraphRAG en `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` presenta varios problemas de rendimiento críticos que afectan gravemente la escalabilidad del sistema: + +### Problemas de Rendimiento Actuales + +**1. Recorrido Ineficiente del Grafo (`follow_edges` function, líneas 79-127)** +- Realiza 3 consultas separadas a la base de datos por entidad y nivel de profundidad. +- Patrón de consulta: consultas basadas en sujeto, predicado y objeto para cada entidad. +- Sin procesamiento por lotes: Cada consulta procesa solo una entidad a la vez. +- Sin detección de ciclos: Puede volver a visitar los mismos nodos varias veces. +- La implementación recursiva sin memorización conduce a una complejidad exponencial. +- Complejidad temporal: O(entidades × max_path_length × triple_limit³) + +**2. Resolución Secuencial de Etiquetas (`get_labelgraph` function, líneas 144-171)** +- Procesa cada componente de triple (sujeto, predicado, objeto) de forma secuencial. +- Cada llamada a `maybe_label` potencialmente desencadena una consulta a la base de datos. +- No hay ejecución paralela ni procesamiento por lotes de las consultas de etiquetas. +- Resulta en hasta 3 consultas individuales a la base de datos por tamaño del subgrafo. + +**3. Estrategia de Almacenamiento en Caché Primitiva (`maybe_label` function, líneas 62-77)** +- Un diccionario de caché simple sin límites de tamaño ni TTL (Time To Live). +- No hay política de desalojo de caché, lo que lleva a un crecimiento ilimitado de la memoria. +- Las fallas de caché desencadenan consultas individuales a la base de datos. +- No hay precarga ni calentamiento inteligente de la caché. + +**4. Patrones de Consulta Subóptimos** +- Las consultas de similitud de vectores de entidades no se almacenan en caché entre solicitudes similares. +- No hay memorización de resultados para patrones de consulta repetidos. +- Faltan optimizaciones de consulta para patrones de acceso comunes. + +**5. Problemas Críticos del Ciclo de Vida de los Objetos (`rag.py:96-102`)** +- **El objeto GraphRag se recrea por solicitud**: Se crea una nueva instancia para cada consulta, perdiendo todos los beneficios de la caché. +- **El objeto Query tiene una vida útil extremadamente corta**: Se crea y destruye dentro de la ejecución de una sola consulta (líneas 201-207). +- **La caché de etiquetas se restablece por solicitud**: El calentamiento de la caché y el conocimiento acumulado se pierden entre las solicitudes. +- **Sobrecarga de recreación del cliente**: Los clientes de la base de datos se restablecen potencialmente para cada solicitud. +- **No hay optimización entre solicitudes**: No se puede beneficiar de patrones de consulta o uso compartido de resultados. + +### Análisis del Impacto en el Rendimiento + +Escenario de peor caso actual para una consulta típica: +- **Recuperación de Entidades**: 1 consulta de similitud de vectores. +- **Recorrido del Grafo**: consultas de entidades × max_path_length × 3 × triple_limit. +- **Resolución de Etiquetas**: consultas individuales de tamaño del subgrafo × 3 de etiquetas. + +Para parámetros predeterminados (50 entidades, longitud de ruta 2, límite de triple 30, tamaño de subgrafo 150): +- **Número mínimo de consultas**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9.451 consultas a la base de datos**. +- **Tiempo de respuesta**: 15-30 segundos para grafos de tamaño moderado. +- **Uso de memoria**: Crecimiento ilimitado de la caché con el tiempo. +- **Eficacia de la caché**: 0% - las cachés se restablecen en cada solicitud. +- **Sobrecarga de creación de objetos**: Se crean/destruyen objetos GraphRag + Query por solicitud. + +Esta especificación aborda estas deficiencias implementando consultas por lotes, almacenamiento en caché inteligente y procesamiento paralelo. Al optimizar los patrones de consulta y el acceso a los datos, TrustGraph puede: +- Compatibilizar con grafos de conocimiento a escala empresarial con millones de entidades. +- Proporcionar tiempos de respuesta de subsegundo para consultas típicas. +- Manejar cientos de solicitudes concurrentes de GraphRAG. +- Escalar de manera eficiente con el tamaño y la complejidad del grafo. + +## Diseño Técnico + +### Arquitectura + +La optimización del rendimiento de GraphRAG requiere los siguientes componentes técnicos: + +#### 1. **Refactorización Arquitectónica del Ciclo de Vida de los Objetos** + - **Hacer que GraphRag tenga una vida útil prolongada**: Mover la instancia de GraphRag al nivel del Procesador para la persistencia entre solicitudes. + - **Preservar las cachés**: Mantener la caché de etiquetas, la caché de incrustaciones y la caché de resultados de consulta entre las solicitudes. + - **Optimizar el objeto Query**: Refactorizar Query como un contexto de ejecución ligero, no como un contenedor de datos. + - **Persistencia de la conexión**: Mantener las conexiones del cliente de la base de datos entre las solicitudes. + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (modificado) + +#### 2. **Motor de Recorrido del Grafo Optimizada** + - Reemplazar `follow_edges` recursivo con una búsqueda en amplitud iterativa. + - Implementar procesamiento por lotes de entidades en cada nivel de recorrido. + - Agregar detección de ciclos utilizando el seguimiento de nodos visitados. + - Incluir finalización temprana cuando se alcanzan los límites. + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` + +#### 3. **Sistema de Resolución de Etiquetas Paralelo** + - Consultas de etiquetas por lotes para múltiples entidades simultáneamente. + - Implementar patrones async/await para el acceso concurrente a la base de datos. + - Agregar precarga inteligente para patrones de etiquetas comunes. + - Incluir estrategias de calentamiento de etiquetas. + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` + +#### 4. **Capa de Almacenamiento en Caché Conservadora** + - Caché LRU con un TTL (Tiempo de Vida) corto para las etiquetas (5 minutos) para equilibrar el rendimiento y la coherencia. + - Métricas de caché y monitoreo de la tasa de aciertos. + - **No se almacena en caché las incrustaciones**: Ya se almacenan en caché por consulta, no hay beneficio entre consultas. + - **No se almacenan en caché los resultados de la consulta**: Debido a las preocupaciones sobre la consistencia de la mutación del grafo. + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` + +#### 5. **Marco de Optimización de Consultas** + - Análisis y sugerencias de optimización de patrones de consulta. + - Coordinador de consultas por lotes para el acceso a la base de datos. + - Pooling de conexiones y gestión de tiempos de espera de consulta. + - Monitoreo de rendimiento y recopilación de métricas. + + Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` + +### Modelos de Datos + +#### Estado de Recorrido del Grafo Optimizada + +El motor de recorrido mantiene el siguiente estado: + +```python +@dataclass +class GraphTraversalState: + current_node: Node + path: List[Node] + visited_nodes: Set[Node] +``` + +#### Caching +```python +class Cache: + def __init__(self, max_size: int): + self.cache = {} + self.max_size = max_size + + def get(self, key): + if key in self.cache: + return self.cache.pop(key) + return None + + def put(self, key, value): + if len(self.cache) >= self.max_size: + # Remove least recently used + oldest_key = next(iter(self.cache)) + del self.cache[oldest_key] + self.cache[key] = value +``` + +#### PerformanceMetrics +```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 +``` + +### Seguridad + +**Prevenir Inyección de Consultas:** +- Validar todos los identificadores de entidad y parámetros de consulta. +- Usar consultas parametrizadas para todas las interacciones con la base de datos. +- Implementar límites de complejidad de consulta para prevenir ataques de denegación de servicio. + +**Protección de Recursos:** +- Hacer cumplir los límites máximos del tamaño del subgrafo. +- Implementar tiempos de espera de consulta para evitar el agotamiento de recursos. +- Agregar monitoreo del uso de la memoria y límites. + +**Control de Acceso:** +- Mantener el aislamiento existente de usuarios y colecciones. +- Agregar registro de auditoría para operaciones que afectan el rendimiento. +- Implementar la limitación de velocidad para las operaciones costosas. + +## Consideraciones de Rendimiento + +### Mejoras de Rendimiento Esperadas + +**Reducción de Consultas:** +- Actual: ~9.000+ consultas por solicitud típica. +- Optimizada: ~50-100 consultas por lotes (reducción del 98%). + +**Mejoras en el Tiempo de Respuesta:** +- Recorrido del grafo: 15-20s → 3-5s (4-5 veces más rápido). +- Resolución de etiquetas: 8-12s → 2-4s (3 veces más rápido). +- Consulta general: 25-35s → 6-10s (mejora de 3-4 veces). + +**Eficiencia de la Memoria:** +- Los tamaños de caché limitados evitan las fugas de memoria. +- Las estructuras de datos eficientes reducen la huella de memoria en un ~40%. +- Mejor recolección de basura a través de una limpieza adecuada de recursos. + +**Mejoras de Escalabilidad:** +- Compatibilidad con grafos de conocimiento 3-5 veces más grandes (limitado por las necesidades de coherencia de la caché). +- Capacidad de solicitud concurrente 3-5 veces mayor. +- Mejor utilización de recursos a través de la reutilización de conexiones. + +### Monitoreo del Rendimiento + +**Métricas en Tiempo Real:** +- Tiempos de ejecución de operaciones por tipo de operación. +- Tasas de aciertos y efectividad de la caché. +- Utilización del grupo de conexiones de la base de datos. +- Uso de memoria y impacto de la recolección de basura. + +**Pruebas de Rendimiento:** +- Pruebas comparativas contra la implementación actual. +- Pruebas de carga con volúmenes de datos realistas. +- Pruebas de estrés para límites de memoria y conexión. +- Pruebas de regresión para mejoras de rendimiento. + +## Estrategia de Pruebas + +### Pruebas Unitarias +- Pruebas de componentes individuales para recorrido, almacenamiento en caché y resolución de etiquetas. +- Interacciones simuladas con la base de datos para pruebas de rendimiento. +- Pruebas de desalojo y expiración de TTL de la caché. +- Escenarios de manejo de errores y tiempo de espera. + +### Pruebas de Integración +- Pruebas de extremo a extremo de la consulta GraphRAG con optimizaciones. +- Pruebas de interacción con la base de datos con datos reales. +- Manejo de solicitudes concurrentes y gestión de recursos. +- Detección de fugas de memoria y verificación de limpieza de recursos. + +### Pruebas de Rendimiento +- Pruebas comparativas contra la implementación actual. +- Pruebas de carga con diferentes tamaños y complejidades de grafos. +- Pruebas de estrés para límites de memoria y conexión. +- Pruebas de regresión para mejoras de rendimiento. + +### Pruebas de Compatibilidad +- Verificar la compatibilidad de la API GraphRAG existente. +- Probar con varios backends de bases de datos de grafos. +- Validar la precisión de los resultados en comparación con la implementación actual. + +## Plan de Implementación + +### Enfoque de Implementación Directa +Dado que se permiten cambios en las API, implemente optimizaciones directamente sin complejidad de migración: + +1. **Reemplace el método `follow_edges`**: Reescriba con un recorrido iterativo por lotes. +2. **Optimice `get_labelgraph`**: Implemente la resolución de etiquetas en paralelo. +3. **Agregue GraphRag de larga duración**: Modifique el Procesador para usar una instancia persistente. +4. **Implemente la estrategia de almacenamiento en caché**: Agregue una capa de caché LRU a la clase GraphRag. + +### Alcance de los Cambios +- **Clase Query**: Reemplace ~50 líneas en `follow_edges`, agregue ~30 líneas de manejo por lotes. +- **Clase GraphRag**: Agregue una capa de almacenamiento en caché (~40 líneas). +- **Clase Procesador**: Modifique para usar una instancia GraphRag persistente (~20 líneas). +- **Total**: ~140 líneas de cambios enfocados, principalmente dentro de clases existentes. + +## Cronograma + +**Semana 1: Implementación Central** +- Reemplace `follow_edges` con un recorrido iterativo por lotes. +- Implemente la resolución de etiquetas en paralelo en `get_labelgraph`. +- Agregue una instancia GraphRag de larga duración al Procesador. +- Implemente la capa de almacenamiento en caché. + +**Semana 2: Pruebas e Integración** +- Pruebas unitarias para la nueva lógica de recorrido y almacenamiento en caché. +- Pruebas comparativas de rendimiento con la implementación actual. +- Pruebas de integración con datos de grafo reales. +- Revisión de código y optimización. + +**Semana 3: Implementación** +- Implemente la implementación optimizada. +- Monitoree las mejoras de rendimiento. +- Ajuste el TTL y los tamaños de lote de la caché en función del uso real. + +## Preguntas Abiertas + +- **Pooling de Conexiones de la Base de Datos**: ¿Deberíamos implementar un pooling de conexiones personalizado o confiar en el pooling de clientes de la base de datos existente? +- **Persistencia de la Caché**: ¿Deberían las cachés de etiquetas y de incrustaciones persistir entre reinicios del servicio? +- **Almacenamiento en Caché Distribuido**: Para implementaciones multi instancia, ¿deberíamos implementar un almacenamiento en caché distribuido con Redis/Memcached? +- **Formato de Resultados de Consulta**: ¿Deberíamos optimizar la representación interna del triple para una mejor eficiencia de la memoria? +- **Integración de Monitoreo**: ¿Qué métricas deben exponerse a los sistemas de monitoreo existentes (Prometheus, etc.)? + +## Referencias + +- [Implementación Original de GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +- [Principios de Arquitectura de TrustGraph](architecture-principles.md) +- [Especificación de Gestión de Colecciones](collection-management.md) \ No newline at end of file diff --git a/docs/tech-specs/graphrag-performance-optimization.he.md b/docs/tech-specs/graphrag-performance-optimization.he.md new file mode 100644 index 00000000..60a650d2 --- /dev/null +++ b/docs/tech-specs/graphrag-performance-optimization.he.md @@ -0,0 +1,101 @@ +# מפרט טכני לאופטימיזציה של ביצועים של GraphRAG + +## סקירה כללית + +מפרט זה מתאר אופטימיזציות מקיפות לביצועים של האלגוריתם GraphRAG (Graph Retrieval-Augmented Generation) ב-TrustGraph. יישום הנוכחי סובל מחסמי ביצועים משמעותיים המגבילים את יכולת ההרחבה וזמני התגובה. מפרט זה מתייחס לארבעה תחומים עיקריים של אופטימיזציה: + +1. **אופטימיזציה של מעבר גרפים**: הסרת שאילתות מסד נתונים רקורסיביות לא יעילות ויישום חקר גרפים בטעינה. +2. **אופטימיזציה של פתרון תגים**: החלפת שליפת תגים רציפה בפעולות מקבילות/בטעינה. +3. **שיפור אסטרטגיית אחסון במטמון**: יישום אחסון במטמון חכם עם פינוי LRU ואחזור מראש. +4. **אופטימיזציה של שאילתות**: הוספת שמירת תוצאות ואחסון במטמון של הטבעות לשיפור זמני התגובה. + +## מטרות + +- **הפחתת נפח שאילתות מסד נתונים**: השגת הפחתה של 50-80% בסך כל שאילתות מסד הנתונים באמצעות טעינה ואחסון במטמון. +- **שיפור זמני תגובה**: כוונון ל-3-5 פעמים מהירות יותר בבניית תת-גרף ו-2-3 פעמים מהירות יותר בפתרון תגים. +- **שיפור יכולת הרחבה**: תמיכה בגרפי ידע גדולים יותר עם ניהול זיכרון טוב יותר. +- **שימור דיוק**: שמירה על הפונקציונליות ואיכות התוצאות של GraphRAG הקיימים. +- **אפשרות לריבוי משימות**: שיפור יכולות עיבוד מקבילי עבור בקשות מקבילות מרובות. +- **הפחתת טביעת רגל של זיכרון**: יישום מבני נתונים וניהול זיכרון יעילים. +- **הוספת יכולת ניטור**: הכללת מדדי ביצועים ויכולות ניטור. +- **הבטחת אמינות**: הוספת טיפול שגיאות ומנגנוני זמן קצובים מתאימים. + +## רקע + +יישום ה-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` עלולה לגרום לשאילתת מסד נתונים. +- ללא ביצוע מקבילי או טעינה של שאילתות תגים. +- גורם עד ל-3 × קריאות מסד נתונים בודדות עבור גודל תת-גרף. + +**3. אסטרטגיית אחסון במטמון בסיסית (פונקציה `maybe_label`, שורות 62-77)** +- מטמון מילון פשוט ללא מגבלות גודל או TTL. +- מדיניות פינוי מטמון חסרה גורמת לצמיחה בלתי מוגבלת של הזיכרון. +- אי-הצלחה במטמון גורמת לשאילתות מסד נתונים בודדות. +- ללא אחזור מראש או חימום מטמון חכם. + +**4. תבניות שאילתות לא אופטימליות** +- שאילתות דמיון וקטורי של ישויות אינן מאוחסנות במטמון בין בקשות דומות. +- ללא שמירת תוצאות לשאילתות דומות. +- אופטימיזציה חסרה של שאילתות לתבניות גישה נפוצות. + +**5. בעיות קריטיות בתוחלת החיים של אובייקטים (`rag.py:96-102`)** +- **אובייקט GraphRag נוצר מחדש עבור כל בקשה**: מופעל מופע חדש עבור כל שאילתה, תוך אובדן כל היתרונות של המטמון. +- **אובייקט שאילתה קצר מועד במיוחד**: נוצר ונהרס במהלך ביצוע שאילתה בודד (שורות 201-207). +- **מטמון תגים מאופס עבור כל בקשה**: חימום מטמון וידע שנצבר אובדים בין בקשות. +- **תקורה של יצירת לקוח**: לקוחות מסד נתונים מוקמים מחדש באופן פוטנציאלי עבור כל בקשה. +- **ללא אופטימיזציה חוצת בקשות**: לא ניתן להפיק תועלת מתבניות שאילתה או שיתוף תוצאות. + +### ניתוח השפעה על ביצועים + +תרחיש גרוע ביותר נוכחי עבור שאילתה טיפוסית: +- **אחזור ישות**: שאילתת דמיון וקטורית אחת. +- **מעבר גרפים**: entities × max_path_length × 3 × triple_limit שאילתות. +- **פתרון תגים**: subgraph_size × 3 שאילתות תגים בודדות. + +עבור פרמטרים ברירת מחדל (50 ישויות, אורך נתיב 2, מגבלת משולש 30, גודל תת-גרף 150): +- **מספר מינימלי של שאילתות**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 שאילתות למסד נתונים** +- **זמן תגובה**: 15-30 שניות עבור גרפים בגודל בינוני. +- **שימוש בזיכרון**: צמיחה בלתי מוגבלת של המטמון לאורך זמן. +- **יעילות מטמון**: 0% - מטמון מאופס בכל בקשה. +- **תקורה של יצירת אובייקטים**: אובייקטי GraphRag + Query נוצרים/נהרסים עבור כל בקשה. + +מפרט זה מתייחס לפערים אלה על ידי יישום שאילתות בטעינה, אחסון במטמון חכם ועיבוד מקבילי. על ידי אופטימיזציה של תבניות שאילתות וגישה לנתונים, TrustGraph יכולה: + +- לתמוך בגרפי ידע בקנה מידה ארגוני עם מיליוני ישויות. +- לספק זמני תגובה של פחות משנייה עבור שאילתות טיפוסיות. +- לטפל במאות בקשות GraphRAG מקבילות. +- להתרחב ביעילות עם גודל ומורכבות הגרף. + +## עיצוב טכני + +### ארכיטקטורה + +אופטימיזציה של ביצועי GraphRAG דורשת את הרכיבים הטכניים הבאים: + +#### 1. **שינוי ארכיטקטורת תוחלת החיים של אובייקטים** + - **הפיכת GraphRag למוחזקת לאורך זמן**: העברת מופע GraphRag לרמת Processor לקבלת עמידות בין בקשות. + - **שמירה על מטמונים**: שמירה על מטמון תגים, מטמון הטבעות ומטמון תוצאות שאילתות בין בקשות. + - **אופטימיזציה של אובייקט שאילתה**: שינוי Query להקשר ביצוע קל משקל, לא מיכל נתונים. + - **שמירת חיבור**: שמירה על חיבורי מסד נתונים לשימוש חוזר. + +#### 2. טעינה ובקשה + - שאילתות יבוצעו בטעינה, המפחיתות את מספר השאילתות הכולל. + +#### 3. אחסון במטמון + - מטמון תגים ישמור תוצאות כדי לשפר את יעילות השאילתה. + +#### 4. מדיניות + - מדיניות שאילתה תאפשר גבולות כדי לשפר את הביצועים. \ No newline at end of file diff --git a/docs/tech-specs/graphrag-performance-optimization.hi.md b/docs/tech-specs/graphrag-performance-optimization.hi.md new file mode 100644 index 00000000..cccdcd26 --- /dev/null +++ b/docs/tech-specs/graphrag-performance-optimization.hi.md @@ -0,0 +1,144 @@ +# ग्राफआरएजी प्रदर्शन अनुकूलन तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ में ग्राफआरएजी (ग्राफ रिट्रीवल-ऑगमेंटेड जनरेशन) एल्गोरिथ्म के लिए व्यापक प्रदर्शन अनुकूलन का वर्णन करता है। वर्तमान कार्यान्वयन महत्वपूर्ण प्रदर्शन बाधाओं से ग्रस्त है जो स्केलेबिलिटी और प्रतिक्रिया समय को सीमित करते हैं। यह विनिर्देश चार प्राथमिक अनुकूलन क्षेत्रों को संबोधित करता है: + +1. **ग्राफ ट्रैवर्सल अनुकूलन**: अक्षम पुनरावर्ती डेटाबेस प्रश्नों को समाप्त करें और बैच किए गए ग्राफ अन्वेषण को लागू करें। +2. **लेबल रिज़ॉल्यूशन अनुकूलन**: अनुक्रमिक लेबल पुनर्प्राप्ति को समानांतर/बैच संचालन से बदलें। +3. **कैशिंग रणनीति में सुधार**: एलआरयू निष्कासन और पूर्व-भार के साथ बुद्धिमान कैशिंग लागू करें। +4. **क्वेरी अनुकूलन**: बेहतर प्रतिक्रिया समय के लिए परिणाम मेमोइजेशन और एम्बेडिंग कैशिंग जोड़ें। + +## लक्ष्य + +- **डेटाबेस क्वेरी की मात्रा को कम करें**: बैचिंग और कैशिंग के माध्यम से कुल डेटाबेस क्वेरी में 50-80% की कमी प्राप्त करें। +- **प्रतिक्रिया समय में सुधार**: उपग्राफ निर्माण में 3-5 गुना तेजी और लेबल रिज़ॉल्यूशन में 2-3 गुना तेजी लाने का लक्ष्य रखें। +- **स्केलेबिलिटी में वृद्धि**: बेहतर मेमोरी प्रबंधन के साथ बड़े नॉलेज ग्राफ का समर्थन करें। +- **सटीकता बनाए रखें**: मौजूदा ग्राफआरएजी कार्यक्षमता और परिणाम गुणवत्ता को संरक्षित करें। +- **समवर्ती को सक्षम करें**: एकाधिक समवर्ती अनुरोधों के लिए समानांतर प्रसंस्करण क्षमताओं में सुधार करें। +- **मेमोरी पदचिह्न को कम करें**: कुशल डेटा संरचनाओं और मेमोरी प्रबंधन को लागू करें। +- **अवलोकनशीलता जोड़ें**: प्रदर्शन मेट्रिक्स और निगरानी क्षमताओं को शामिल करें। +- **विश्वसनीयता सुनिश्चित करें**: उचित त्रुटि प्रबंधन और टाइमआउट तंत्र जोड़ें। + +## पृष्ठभूमि + +`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` कॉल संभावित रूप से एक डेटाबेस क्वेरी को ट्रिगर करता है। +- लेबल क्वेरी का कोई समानांतर निष्पादन या बैचिंग नहीं। +- प्रति उपग्राफ आकार में 3 अलग डेटाबेस कॉल होते हैं। + +**3. आदिम कैशिंग रणनीति (`maybe_label` फ़ंक्शन, लाइनें 62-77)** +- बिना आकार सीमा या टीटीएल के सरल शब्दकोश कैश। +- कोई कैश निष्कासन नीति नहीं है, जिससे असीमित मेमोरी वृद्धि होती है। +- कैश मिस व्यक्तिगत डेटाबेस क्वेरी को ट्रिगर करते हैं। +- कोई पूर्व-भार या बुद्धिमान कैश वार्मिंग नहीं है। + +**4. उप-इष्टतम क्वेरी पैटर्न** +- समान अनुरोधों के बीच इकाई वेक्टर समानता क्वेरी का कैश नहीं किया जाता है। +- दोहराए गए क्वेरी पैटर्न के लिए कोई परिणाम मेमोइजेशन नहीं है। +- सामान्य एक्सेस पैटर्न के लिए क्वेरी अनुकूलन गायब है। + +**5. महत्वपूर्ण ऑब्जेक्ट लाइफटाइम मुद्दे (`rag.py:96-102`)** +- **प्रत्येक अनुरोध के लिए GraphRag ऑब्जेक्ट फिर से बनाया गया**: प्रत्येक क्वेरी के लिए एक नया उदाहरण बनाया जाता है, जिससे सभी कैश लाभ खो जाते हैं। +- **क्वेरी ऑब्जेक्ट बहुत कम समय तक जीवित रहता है**: एक ही क्वेरी निष्पादन के भीतर बनाया और नष्ट किया जाता है (लाइनें 201-207)। +- **प्रत्येक अनुरोध के लिए लेबल कैश रीसेट किया जाता है**: कैश वार्मिंग और संचित ज्ञान अनुरोधों के बीच खो जाता है। +- **क्लाइंट पुनर्निर्माण ओवरहेड**: प्रत्येक अनुरोध के लिए डेटाबेस क्लाइंट संभावित रूप से फिर से स्थापित किए जाते हैं। +- **कोई क्रॉस-अनुरोध अनुकूलन नहीं**: क्वेरी पैटर्न या परिणाम साझाकरण से लाभ नहीं हो सकता है। + +### प्रदर्शन प्रभाव विश्लेषण + +एक विशिष्ट क्वेरी के लिए वर्तमान सबसे खराब स्थिति परिदृश्य: +- **इकाई पुनर्प्राप्ति**: 1 वेक्टर समानता क्वेरी +- **ग्राफ ट्रैवर्सल**: entities × max_path_length × 3 × triple_limit क्वेरी +- **लेबल रिज़ॉल्यूशन**: subgraph_size × 3 व्यक्तिगत लेबल क्वेरी + +डिफ़ॉल्ट मापदंडों के लिए (50 इकाइयां, पथ लंबाई 2, 30 ट्रिपल सीमा, 150 उपग्राफ आकार): +- **न्यूनतम क्वेरी**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 डेटाबेस क्वेरी** +- **प्रतिक्रिया समय**: मध्यम आकार के ग्राफ के लिए 15-30 सेकंड +- **मेमोरी उपयोग**: समय के साथ असीमित कैश वृद्धि +- **कैश प्रभावशीलता**: 0% - प्रत्येक अनुरोध पर कैश रीसेट होते हैं +- **ऑब्जेक्ट निर्माण ओवरहेड**: GraphRag + Query ऑब्जेक्ट प्रति अनुरोध बनाए जाते हैं/नष्ट किए जाते हैं + +यह विनिर्देश बैच किए गए प्रश्नों, बुद्धिमान कैशिंग और समानांतर प्रसंस्करण को लागू करके इन कमियों को संबोधित करता है। क्वेरी पैटर्न और डेटा एक्सेस को अनुकूलित करके, ट्रस्टग्राफ: +- लाखों इकाइयों के साथ उद्यम-स्तरीय नॉलेज ग्राफ का समर्थन कर सकता है। +- विशिष्ट क्वेरी के लिए उप-सेकंड प्रतिक्रिया समय प्रदान कर सकता है। +- सैकड़ों समवर्ती GraphRAG अनुरोधों को संभाल सकता है। +- ग्राफ आकार और जटिलता के साथ कुशलतापूर्वक स्केल कर सकता है। + +## तकनीकी डिजाइन + +### आर्किटेक्चर + +ग्राफआरएजी प्रदर्शन अनुकूलन के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: + +#### 1. **ऑब्जेक्ट लाइफटाइम आर्किटेक्चरल रीफैक्टर** + - **GraphRag को लंबे समय तक चलने वाला बनाएं**: GraphRag उदाहरण को प्रोसेसर स्तर पर लगातार रहने के लिए स्थानांतरित करें। + - **कैश को संरक्षित करें**: अनुरोधों के बीच लेबल कैश, एम्बेडिंग कैश और क्वेरी परिणाम कैश बनाए रखें। + - **क्वेरी ऑब्जेक्ट को अनुकूलित करें**: क्वेरी को एक हल्के निष्पादन संदर्भ, डेटा कंटेनर के रूप में रीफैक्टर करें। + - **कनेक्शन दृढ़ता**: अनुरोधों में डेटाबेस क्लाइंट कनेक्शन बनाए रखें। + + मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (संशोधित) + +#### 2. **अनुकूलित ग्राफ ट्रैवर्सल इंजन** + - पुनरावर्ती `follow_edges` को पुनरावृत्त चौड़ाई-पहली खोज से बदलें। + - प्रत्येक ट्रैवर्सल स्तर पर बैच किए गए इकाई प्रसंस्करण को लागू करें। + - देखे गए नोड ट्रैकिंग का उपयोग करके चक्र का पता लगाएं। + - सीमाओं तक पहुंचने पर प्रारंभिक समाप्ति शामिल करें। + + मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` + +#### 3. **समानांतर लेबल रिज़ॉल्यूशन सिस्टम** + - एक साथ कई इकाइयों के लिए लेबल क्वेरी को बैच करें। + - समवर्ती डेटाबेस एक्सेस के लिए एसिंक्रोनस/अवेट पैटर्न लागू करें। + - सामान्य लेबल पैटर्न के लिए बुद्धिमान पूर्व-भार जोड़ें। + - लेबल कैश वार्मिंग रणनीतियों को शामिल करें। + + मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` + +#### 4. **रूढ़िवादी लेबल कैशिंग परत** + - प्रदर्शन बनाम स्थिरता को संतुलित करने के लिए केवल लेबल के लिए एलआरयू कैश (5 मिनट) के साथ छोटा टीटीएल। + - कैश मेट्रिक्स और हिट अनुपात निगरानी। + - **कोई एम्बेडिंग कैशिंग नहीं**: पहले से ही प्रति-क्वेरी कैश किया गया, कोई क्रॉस-क्वेरी लाभ नहीं। + - **कोई क्वेरी परिणाम कैशिंग नहीं**: ग्राफ परिवर्तन स्थिरता संबंधी चिंताओं के कारण। + + मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` + +#### 5. **क्वेरी अनुकूलन ढांचा** + - क्वेरी पैटर्न विश्लेषण और अनुकूलन सुझाव। + - डेटाबेस एक्सेस के लिए बैच क्वेरी समन्वयक। + - कनेक्शन पूलिंग और क्वेरी टाइमआउट प्रबंधन। + - प्रदर्शन निगरानी और मेट्रिक्स संग्रह। + + मॉड्यूल: `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] +``` + +#### \ No newline at end of file diff --git a/docs/tech-specs/graphrag-performance-optimization.ru.md b/docs/tech-specs/graphrag-performance-optimization.ru.md new file mode 100644 index 00000000..c69fddca --- /dev/null +++ b/docs/tech-specs/graphrag-performance-optimization.ru.md @@ -0,0 +1,124 @@ +# Техническое задание по оптимизации производительности GraphRAG + +## Обзор + +Данное техническое задание описывает комплексные оптимизации производительности алгоритма GraphRAG (Graph Retrieval-Augmented Generation) в системе TrustGraph. Текущая реализация страдает от существенных проблем с производительностью, которые ограничивают масштабируемость и время отклика. Данное задание охватывает четыре основные области оптимизации: + +1. **Оптимизация обхода графа**: Устранение неэффективных рекурсивных запросов к базе данных и реализация пакетной обработки графа. +2. **Оптимизация разрешения меток**: Замена последовательной выборки меток параллельными/пакетными операциями. +3. **Улучшение стратегии кэширования**: Реализация интеллектуального кэширования с вытеснением по алгоритму LRU и предварительной загрузкой. +4. **Оптимизация запросов**: Добавление мемоизации результатов и кэширования векторов для повышения скорости отклика. + +## Цели + +- **Сокращение количества запросов к базе данных**: Достижение снижения общего количества запросов к базе данных на 50-80% за счет пакетной обработки и кэширования. +- **Улучшение времени отклика**: Ускорение построения подграфа в 3-5 раза и ускорение разрешения меток в 2-3 раза. +- **Повышение масштабируемости**: Поддержка более крупных графовых баз знаний с улучшением управления памятью. +- **Сохранение точности**: Сохранение существующей функциональности GraphRAG и качества результатов. +- **Обеспечение параллельности**: Улучшение возможностей параллельной обработки для множества одновременных запросов. +- **Уменьшение занимаемой памяти**: Реализация эффективных структур данных и управления памятью. +- **Добавление наблюдаемости**: Включение метрик производительности и возможностей мониторинга. +- **Обеспечение надежности**: Добавление механизмов обработки ошибок и таймаутов. + +## Описание проблемы + +Текущая реализация GraphRAG, находящаяся в файле `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py`, имеет ряд критических проблем с производительностью, которые серьезно влияют на масштабируемость системы: + +### Текущие проблемы с производительностью + +**1. Неэффективный обход графа (`follow_edges` function, строки 79-127)** +- Выполняет 3 отдельных запроса к базе данных для каждой сущности на каждом уровне глубины. +- Шаблон запроса: запросы на основе субъекта, предиката и объекта для каждой сущности. +- Отсутствие пакетной обработки: Каждый запрос обрабатывает только одну сущность за раз. +- Отсутствие обнаружения циклов: Может повторно посещать одни и те же узлы несколько раз. +- Рекурсивная реализация без мемоизации приводит к экспоненциальной сложности. +- Временная сложность: O(entities × max_path_length × triple_limit³) + +**2. Последовательное разрешение меток (`get_labelgraph` function, строки 144-171)** +- Обрабатывает каждый компонент тройки (субъект, предикат, объект) последовательно. +- Каждый вызов `maybe_label` потенциально вызывает запрос к базе данных. +- Отсутствует параллельное выполнение или пакетная обработка запросов меток. +- Приводит до 3 × subgraph_size отдельных запросов к базе данных. + +**3. Примитивная стратегия кэширования (`maybe_label` function, строки 62-77)** +- Простой кэш в виде словаря без ограничений размера или TTL. +- Отсутствие политики вытеснения из кэша приводит к неограниченному росту использования памяти. +- Пропуски в кэше вызывают отдельные запросы к базе данных. +- Отсутствует предварительная загрузка или интеллектуальное "прогрев" кэша. + +**4. Субоптимальные шаблоны запросов** +- Запросы на поиск сходства векторов сущностей не кэшируются между похожими запросами. +- Отсутствует мемоизация результатов для повторяющихся шаблонов запросов. +- Отсутствует оптимизация запросов для распространенных сценариев доступа. + +**5. Критические проблемы с временем жизни объектов (`rag.py:96-102`)** +- **Объект GraphRag пересоздается для каждого запроса**: Новый экземпляр создается для каждого запроса, что приводит к потере всех преимуществ кэширования. +- **Объект Query имеет очень короткое время жизни**: Создается и уничтожается в рамках выполнения одного запроса (строки 201-207). +- **Кэш меток сбрасывается для каждого запроса**: "Прогрев" кэша и накопленные знания теряются между запросами. +- **Накладные расходы на повторное создание клиента**: Клиенты базы данных потенциально переподключаются для каждого запроса. +- **Отсутствует оптимизация между запросами**: Невозможно воспользоваться преимуществами шаблонов запросов или совместного использования результатов. + +### Анализ влияния на производительность + +Текущий наихудший сценарий для типичного запроса: +- **Извлечение сущности**: 1 запрос на поиск сходства векторов. +- **Обход графа**: entities × max_path_length × 3 × triple_limit запросов. +- **Разрешение меток**: subgraph_size × 3 отдельных запросов на метки. + +Для параметров по умолчанию (50 сущностей, глубина 2, лимит 30 троек, размер подграфа 150): +- **Минимальное количество запросов**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 запросов к базе данных**. +- **Время отклика**: 15-30 секунд для графов умеренного размера. +- **Использование памяти**: Неограниченный рост кэша со временем. +- **Эффективность кэша**: 0% - кэш сбрасывается при каждом запросе. +- **Накладные расходы на создание объектов**: Объекты GraphRag + Query создаются/уничтожаются для каждого запроса. + +Данное техническое задание решает эти проблемы путем реализации пакетных запросов, интеллектуального кэширования и параллельной обработки. Оптимизируя шаблоны запросов и доступ к данным, TrustGraph может: + +- Поддерживать графовые базы знаний предприятия с миллионами сущностей. +- Обеспечивать время отклика менее 1 секунды для типичных запросов. +- Обрабатывать сотни одновременных запросов GraphRAG. +- Эффективно масштабироваться с ростом размера и сложности графа. + +## Технический дизайн + +### Архитектура + +Оптимизация производительности GraphRAG требует следующих технических компонентов: + +#### 1. **Архитектурная реорганизация для управления временем жизни объектов** + - **Сделать GraphRag долгоживущим**: Перенести экземпляр GraphRag на уровень Processor для сохранения данных между запросами. + - **Сохранить кэши**: Поддерживать кэш меток, кэш векторов и кэш результатов запросов между запросами. + - **Оптимизировать объект Query**: Рефакторинг Query как легковесного контекста выполнения, а не контейнера данных. + - **Сохранение подключений**: Поддерживать подключения к базе данных между запросами. + + Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (изменен) + +#### 2. **Оптимизированный движок обхода графа** + - Заменить рекурсивный `follow_edges` итеративным поиском в ширину. + - Реализовать пакетную обработку сущностей на каждом уровне обхода. + - Добавить обнаружение циклов с отслеживанием посещенных узлов. + - Включить раннее завершение при достижении лимитов. + + Модуль: `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 минут) для баланса между производительностью и согласованностью. + - Мониторинг метрик кэша и коэффициента попадания. + - **Без кэширования векторов**: Уже кэшируются на уровне запроса, нет пользы для между запросами. + - **Без кэширования результатов запросов**: Из-за проблем согласованности данных в графе. + + Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` + +#### 5. **Фреймворк оптимизации запросов** + - Анализ шаблонов запросов и предложения по оптимизации. + - Координатор пакетных запросов для доступа к базе данных. + - Пулинг подключений и управление таймаутами запросов. + - Мониторинг производительности. \ No newline at end of file diff --git a/docs/tech-specs/graphrag-performance-optimization.sw.md b/docs/tech-specs/graphrag-performance-optimization.sw.md new file mode 100644 index 00000000..2b07ce51 --- /dev/null +++ b/docs/tech-specs/graphrag-performance-optimization.sw.md @@ -0,0 +1,240 @@ +# GraphRAG Utendaji Uboreshaji Maelezo ya Kiufundi + +## Muhtasari + +Maelezo haya yanaeleza uboreshaji kamili wa utendaji wa algorithm ya GraphRAG (Graph Retrieval-Augmented Generation) katika TrustGraph. Matumizi ya sasa yana vizuizi vya utendaji muhimu ambavyo hu limit scalability na muda wa majibu. Maelezo haya yanashughulikia maeneo manne makuu ya uboreshaji: + +1. **Uboreshaji wa Ufuatiliaji wa Grafu**: Ondoa maswali ya hivi karibuni ya database na utumie utafiti wa kikundi. +2. **Uboreshaji wa Utatuzi wa Labe**: Badilisha upataji wa mlolongo wa lebo kwa operesheni za sambamba/kikundi. +3. **Uboreshaji wa Mkakati wa Kumbukumbu**: Implement caching kwa akili pamoja na uondoshaji wa LRU na utaratibu wa kupata data. +4. **Uboreshaji wa Maswali**: Ongeza kumbukumbu ya matokeo na caching ya embeddings ili kuboresha muda wa majibu. + +## Malengo + +- **Punguza Idadi ya Maswali ya Database**: Punguza kwa 50-80% jumla ya maswali ya database kupitia kikundi na caching. +- **Boresha Muda wa Majibu**: Lenga ujenzi wa subgraph wa haraka 3-5x na utatuzi wa lebo wa haraka 2-3x. +- **Boresha Scalability**: Unga grafu kubwa zaidi za maarifa na usimamizi bora wa kumbukumbu. +- **Dumishe Usahihi**: Dumishe utendakazi na ubora wa matokeo ya GraphRAG iliyopo. +- **Wezesha Ujazo**: Boresha uwezo wa usindikaji sambamba kwa maombi mengi sambamba. +- **Punguza Uwepo wa Kumbukumbu**: Implement miundo ya data na usimamizi wa kumbukumbu bora. +- **Ongeza Ufuatiliaji**: Jumuisha metriki za utendaji na uwezo wa ufuatiliaji. +- **Hakikisha Utiaji Njia**: Ongeza utunzaji sahihi wa makosa na mitaratibu ya muda. + +## Asili + +Matumizi ya sasa ya GraphRAG katika `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` ina masuala muhimu ya utendaji ambayo yanaathiri sana scalability ya mfumo: + +### Matatizo ya Sasa ya Utendaji + +**1. Ufuatiliaji Usio na Ufanisi wa Grafu (`follow_edges` function, mistari 79-127)** +- Hufanya maswali 3 tofauti ya database kwa kila entiti kwa kila ngazi. +- Mfumo wa swali: maswali yanayozingatia mada, yanayozingatia predikat, na yanayozingatia kitu kwa kila entiti. +- Hakuna kikundi: Kila swali hutumia entiti moja tu wakati mmoja. +- Hakuna ugunduzi wa mzunguko: Inaweza kutembelea nodi sawa mara nyingi. +- Matumizi ya recursive bila kumbukumbu hupelekea utata wa kielelekeo. +- Utata wa muda: O(entities × max_path_length × triple_limit³) + +**2. Utatuzi Mfululizo wa Labe (`get_labelgraph` function, mistari 144-171)** +- Hufanya usindikaji wa kila sehemu ya triple (mada, predikat, kitu) mfululizo. +- Kila wito wa `maybe_label` inaweza kusababisha swali la database. +- Hakuna utekelezaji au kikundi sambamba wa maswali ya lebo. +- Hupelekea hadi simu 3 × subgraph_size za database. + +**3. Mkakati wa Msingi wa Kumbukumbu (`maybe_label` function, mistari 62-77)** +- Cache rahisi ya kamusi bila mipaka ya saizi au TTL. +- Hakuna sera ya kuondolewa kwa cache hupelekea ukuaji usio na kikomo wa kumbukumbu. +- Upotezaji wa cache husababisha maswali ya database ya kibinafsi. +- Hakuna kupata data au uongezaji mahiri wa cache. + +**4. Mfumo Usio bora wa Maswali** +- Maswali ya ufanano wa vector ya entiti hayahifadhiwi kati ya maombi sawa. +- Hakuna kumbukumbu ya matokeo kwa mifumo ya swali iliyorudiwa. +- Uboreshaji wa maswali unokosekana kwa mifumo ya kawaida ya ufikiaji. + +**5. Masuala Muhimu ya Muda wa Kitu (`rag.py:96-102`)** +- **Kitu cha GraphRag kinaundwa kila maombi**: Instance mpya huundwa kwa kila swali, na kupoteza faida zote za cache. +- **Kitu cha swali kina muda mfupi sana**: Huundwa na kuharibiwa ndani ya utekelezaji wa swali moja (mistari 201-207). +- **Cache ya lebo huwezeshwa kila maombi**: Uongezaji wa cache na maarifa yaliyokusanywa hayapotei kati ya maombi. +- **Utoaji wa upya wa mteja**: Wateja wa database wanaweza kuanzishwa tena kwa kila maombi. +- **Uboreshaji usio na maombi**: Haiwezi kufaidika na mifumo ya swali au kushiriki matokeo. + +### Uchambuzi wa Athari za Utendaji + +Jalada la mbaya zaidi linalowezekana kwa swali la kawaida: +- **Uongezaji wa Entiti**: Swali 1 la ufanano wa vector +- **Ufuatiliaji wa Grafu**: entities × max_path_length × 3 × maswali ya triple_limit +- **Utatuzi wa Labe**: maswali ya lebo ya `subgraph_size` × 3 ya kibinafsi + +Kwa vigezo vya chagu msingi (entities 50, urefu wa njia 2, kikomo cha triple 30, saizi ya subgraph 150): +- **Maswali ya chini**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **maswali 9,451 ya database** +- **Muda wa majibu**: 15-30 sekunde kwa grafu za ukubwa wa wastani +- **Matumizi ya kumbukumbu**: Ukuaji usio na kikomo wa cache baada ya muda +- **Ufanisi wa cache**: 0% - caches huwezeshwa kila maombi +- **Utoaji wa kitu**: Kitu cha GraphRag + Kitu cha swali kinaundwa/kuharibiwa kwa kila maombi + +Maelezo haya yanashughulikia pengo hizi kwa kutumia maswali ya kikundi, caching kwa akili, na usindikaji sambamba. Kwa kuongeza ufanisi wa mifumo ya swali na ufikiaji wa data, TrustGraph inaweza: +- Unga grafu kubwa za maarifa na milioni ya entiti +- Kutoa muda wa majibu wa chini ya sekunde kwa swali la kawaida +- Kushughulikia maombi ya GraphRAG ya sambamba mamia +- Kuongezeka kwa ufanisi na saizi na utata wa grafu + +## Ubunifu wa Kiufundi + +### Usanifu + +Uboreshaji wa utendaji wa GraphRAG unahitaji vipengele hivi vya kiufundi: + +#### 1. **Urekebishaji wa Usanifu wa Muda wa Kitu** + - **Fanya GraphRag kuwa wa muda mrefu**: Hamisha instance ya GraphRag hadi ngazi ya Processor ili kudumu katika maombi. + - **Dumishe caches**: Dumishe cache ya lebo, cache ya embedding, na cache ya matokeo ya swali kati ya maombi. + - **Boresha Kitu cha Swali**: Rekebisha Swali kama muktadha wa utekelezaji nyepesi, sio kontena ya data. + - **Usaidizi wa miunganisho**: Dumishe miunganisho ya mteja wa database katika maombi. + + Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (imebadilishwa) + +#### 2. **Njia Iliyo bora ya Ufuatiliaji wa Grafu** + - Badilisha `follow_edges` ya recursive na utafutaji wa msingi wa upana wa iterative + - Implement utunzaji wa kikundi wa entiti katika kila ngazi ya utafutaji +- Ongeza ugunduzi wa mzunguko kwa kufuatilia nodi zilizotembelea +- Jumuisha kumalizika mapema wakati mipaka inafikiwa + + Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` + +#### 3. **Mfumo Sambamba wa Utatuzi wa Labe** + - Kundi maswali ya lebo kwa entiti nyingi wakati mmoja + - Implement mifumo ya async/kusubiri kwa ufikiaji wa sambamba wa database + - Ongeza kupata data mahiri kwa mifumo ya kawaida ya lebo + - Jumusha mikakati ya uongezaji wa lebo + + Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolution.py` + +#### 4. **Mkakati wa Kina wa Kumbukumbu** +- Implement cache ya LRU na TTL +- Zana za ufuatiliaji wa utendaji wa cache +- Usalama wa maswali na utunzaji wa rasilimali + +**Mbinu ya Ufuatiliaji ya Kumbukumbu**: +```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() +``` + +#### 5. **Uboreshaji wa Swali na Ufuatiliaji** +- **Ukusanyaji wa Metriki za Utendaji**: +- **Upekuzi na Muda**: +- **Usimamizi wa Rasilimali**: +- **Ufuatiliaji**: + +**Muda wa Majibu**: +- Ufuatiliaji wa utendaji wa GraphRAG +- Ufuatiliaji wa maswali ya database +- Ufuatiliaji wa matumizi ya kumbukumbu +- Ufuatiliaji wa utekelezaji wa maombi + +## Mkakati wa Kujaribu + +### Kujaribu Kawaida +- Kujaribu sehemu kwa sehemu kwa utafutaji, caching, na utatuzi wa lebo +- Ujaribu bandia wa mashambulio ya database kwa utendaji +- Kujaribu cache ya uondoshaji na utekelezaji wa TTL +- Kujaribu utunzaji na muda wa makosa + +### Kujaribu Kuunganisha +- Kujaribu swali la GraphRAG kamili na uboreshaji +- Kujaribu mashambulio ya database ya kweli +- Kujaribu uendeshaji sambamba na usimamizi wa rasilimali +- Kujaribu ugunduzi na usimamizi wa rasilimali +- Kujaribu utangamano na API iliyopo ya GraphRAG +- Kujaribu na nyuma tofauti za database +- Kuhakikisha usahihi wa matokeo ikilinganisha na utumizi wa sasa + +### Kujaribu Utendaji +- Kujaribu utendaji dhidi ya utumizi wa sasa +- Kujaribu mzigo kwa saizi tofauti na utata wa grafu +- Kujaribu shinikizo kwa mipaka ya kumbukumbu na muunganisho +- Kujaribu utangamano kwa uboreshaji wa utendaji + +### Kujaribu Utangamano +- Hakikisha utangamano wa API ya GraphRAG iliyopo +- Jaribu na nyuma tofauti za database +- Hakikisha usahihi wa matokeo ikilinganisha na utumizi wa sasa + +## Mpango wa Utekelezaji + +### Njia ya Utekelezaji Moja kwa Moja +Kwa kuwa API zinaidhinishwa kubadilika, implement uboreshaji moja kwa moja bila utata wa uhamishaji: + +1. **Badilisha njia ya `follow_edges`**: Andika upya na utafutaji ulioidhinishwa wa kikundi +2. **Boresha `get_labelgraph`**: Implement utatuzi sambamba wa lebo +3. **Ongeza GraphRag ya muda mrefu**: Badilisha Processor ili itumie instance ya GraphRag iliyodumu +4. **Implement cache ya lebo**: Ongeza safu ya caching kwenye darasa la GraphRag + +### Nguvu ya Marekebisho +- **Darasa la swali**: Badilisha ~50 mistari katika `follow_edges`, ongeza ~30 mistari ya utunzaji wa kikundi +- **Darasa la GraphRag**: Ongeza safu ya caching (~40 mistari) +- **Darasa la Processor**: Badilisha ili utumie instance ya GraphRag iliyodumu (~20 mistari) +- **Jumla**: ~140 mistari ya mabadiliko iliyolengwa, haswa ndani ya madarasa yaliyopo + +## Ratiba + +**Wiki ya 1: Utumizi wa Msingi** +- Badilisha `follow_edges` na utafutaji wa kikundi wa iterative +- Implement utatuzi wa sambamba wa lebo katika `get_labelgraph` +- Ongeza instance ya GraphRag iliyodumu kwa Processor +- Implement safu ya caching ya lebo + +**Wiki ya 2: Kujaribu na Kuunganisha** +- Kujaribu kawaida kwa mantiki mpya ya utafutaji na caching +- Kujaribu utendaji dhidi ya utumizi wa sasa +- Kujaribu kuunganisha na data ya grafu ya kweli +- Tathmini ya msimamizi wa msimamizi wa msimamizi wa msimamizi wa msimamizi +- Kujaribu utangamano + +**Wiki ya 3: Utekelezaji** +- Tepeleza utumizi uliorekebishwa +- Fuatilia uboreshaji wa utendaji +- Rekebisha TTL ya cache na saizi za kikundi kulingana na matumizi halisi + +## Maswali Yaliyofungwa + +- **Pooli ya Muunganisho wa Database**: Je, tunapaswa kutumia pooli ya muunganisho ya database maalum au kutegemea pooli ya mteja wa database iliyopo? +- **Usaidizi wa Kumbukumbu**: Je, cache ya lebo na ya embedding inapaswa kuendelea katika kuchelewesha huduma? +- **Kumbukumbu Iliyosambaa**: Kwa usimamizi wa idadi nyingi, je, tunapaswa kutumia kumbukumbu iliyosambaa kwa Redis/Memcached? +- **Umbizo la Matokeo ya Swali**: Je, tunapaswa kuongeza ufanisi wa uwakilishi wa ndani wa triple kwa ufanisi bora wa kumbukumbu? +- **Uunganisho wa Ufuatiliaji**: Metriki gani zinapaswa kuonyeshwa kwenye mifumo ya ufuatiliaji iliyopo (Prometheus, n.k.)? + +## Marejeleo + +- [Utekelezaji wa awali wa GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +- [Kanuni za Usanifu za TrustGraph](architecture-principles.md) +- [Maelezo ya Usimamizi wa Mkusanyiko](collection-management.md) \ No newline at end of file diff --git a/docs/tech-specs/graphrag-performance-optimization.zh-cn.md b/docs/tech-specs/graphrag-performance-optimization.zh-cn.md new file mode 100644 index 00000000..77ed6312 --- /dev/null +++ b/docs/tech-specs/graphrag-performance-optimization.zh-cn.md @@ -0,0 +1,364 @@ +# GraphRAG 性能优化技术规范 + +## 概述 + +本规范描述了 TrustGraph 中 GraphRAG(基于图的检索增强生成)算法的全面性能优化。当前的实现存在严重的性能瓶颈,限制了可扩展性和响应时间。本规范解决了四个主要优化领域: + +1. **图遍历优化**: 消除低效的递归数据库查询,并实现批处理图探索。 +2. **标签解析优化**: 替换顺序标签获取方式,采用并行/批处理操作。 +3. **缓存策略增强**: 实现智能缓存,采用 LRU 淘汰策略和预取。 +4. **查询优化**: 添加结果备忘和嵌入缓存,以提高响应时间。 + +## 目标 + +- **减少数据库查询量**: 通过批处理和缓存,实现总数据库查询量的 50-80% 减少。 +- **提高响应时间**: 目标是子图构建速度提升 3-5 倍,标签解析速度提升 2-3 倍。 +- **增强可扩展性**: 支持更大的知识图谱,并改进内存管理。 +- **保持准确性**: 保持现有的 GraphRAG 功能和结果质量。 +- **启用并发性**: 提高并行处理能力,支持多个并发请求。 +- **减少内存占用**: 实施高效的数据结构和内存管理。 +- **增加可观察性**: 包含性能指标和监控功能。 +- **确保可靠性**: 添加适当的错误处理和超时机制。 + +## 背景 + +`trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` 中当前的 GraphRAG 实现存在以下关键性能问题,严重影响系统可扩展性: + +### 当前性能问题 + +**1. 低效的图遍历 (`follow_edges` 函数,第 79-127 行)** +- 对每个实体、每个深度级别执行 3 次独立的数据库查询。 +- 查询模式:针对每个实体的基于主体、基于谓词和基于对象的查询。 +- 没有批处理:每次查询只处理一个实体。 +- 没有循环检测:可能多次访问相同的节点。 +- 没有备忘功能的递归实现会导致指数级复杂度。 +- 时间复杂度:O(entities × max_path_length × triple_limit³) + +**2. 顺序标签解析 (`get_labelgraph` 函数,第 144-171 行)** +- 顺序处理每个三元组组件(主体、谓词、对象)。 +- 每次 `maybe_label` 调用可能触发数据库查询。 +- 没有并行执行或批处理标签查询。 +- 导致最多 subgraph_size × 3 次独立的数据库调用。 + +**3. 原始缓存策略 (`maybe_label` 函数,第 62-77 行)** +- 简单的字典缓存,没有大小限制或 TTL(生存时间)。 +- 没有缓存淘汰策略导致内存无限增长。 +- 缓存未命中会触发单独的数据库查询。 +- 没有预取或智能缓存预热。 + +**4. 不佳的查询模式** +- 实体向量相似度查询未在相似请求之间缓存。 +- 没有重复查询模式的结果备忘。 +- 缺少常见访问模式的查询优化。 + +**5. 关键的对象生命周期问题 (`rag.py:96-102`)** +- **`GraphRag` 对象每个请求都重新创建**: 每次查询都会创建新的实例,失去所有缓存优势。 +- **`Query` 对象生存时间极短**: 创建并销毁于单个查询执行中 (第 201-207 行)。 +- **标签缓存每个请求都重置**: 缓存预热和积累的知识在请求之间丢失。 +- **客户端重新创建开销**: 数据库客户端可能为每个请求重新建立连接。 +- **没有跨请求优化**: 无法从查询模式或结果共享中受益。 + +### 性能影响分析 + +当前典型的查询最坏情况: +- **实体检索**: 1 次向量相似度查询。 +- **图遍历**: entities × max_path_length × 3 × triple_limit 次查询。 +- **标签解析**: subgraph_size × 3 次独立的标签查询。 + +对于默认参数(50 个实体,路径长度 2,30 个三元组限制,150 个子图大小): +- **最小查询次数**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 次数据库查询** +- **响应时间**: 中等大小图的响应时间为 15-30 秒。 +- **内存使用**: 缓存无限增长。 +- **缓存有效性**: 0% - 每次请求都重置缓存。 +- **对象创建开销**: 为每个请求创建/销毁 `GraphRag` + `Query` 对象。 + +本规范通过实施批处理查询、智能缓存和并行处理来解决这些问题。 通过优化查询模式和数据访问,TrustGraph 可以: +- 支持数百万个实体的企业级知识图谱。 +- 为典型的查询提供亚秒级的响应时间。 +- 处理数百个并发的 GraphRAG 请求。 +- 通过图的大小和复杂性实现高效扩展。 + +## 技术设计 + +### 架构 + +GraphRAG 性能优化需要以下技术组件: + +#### 1. **对象生命周期架构重构** + - **使 `GraphRag` 长期存在**: 将 `GraphRag` 实例移动到 Processor 级别,以在请求之间保持持久性。 + - **保留缓存**: 保持标签缓存、嵌入缓存和查询结果缓存在请求之间。 + - **优化 `Query` 对象**: 将 `Query` 重构为轻量级执行上下文,而不是数据容器。 + - **连接持久化**: 在请求之间保持数据库客户端连接。 + + 模块: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (已修改) + +#### 2. **优化的图遍历引擎** + - 将递归的 `follow_edges` 替换为迭代的广度优先搜索。 + - 在每个遍历级别实施批处理实体处理。 + - 添加循环检测,使用已访问节点跟踪。 + - 包含当达到限制时提前终止。 + + 模块: `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 分钟)用于仅限标签,以平衡性能与一致性。 + - 缓存指标和命中率监控。 + - **不缓存嵌入**: 已针对每个查询进行缓存,没有跨查询的优势。 + - **不缓存查询结果**: 由于图的mutation一致性问题。 + + 模块: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` + +#### 5. **查询优化框架** + - 查询模式分析和优化建议。 + - 数据库访问的批处理查询协调器。 + - 连接池和查询超时管理。 + - 性能监控和指标收集。 + + 模块: `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** +```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: str, result: Any, timeout: int = 3600) + def total_cache_size(self) -> int +``` + +#### 接口变更 + +**查询类**: 将 `follow_edges` 方法替换为批处理迭代遍历 +**GraphRag 类**: 添加标签缓存层 +**Processor 类**: 修改以使用持久的 `GraphRag` 实例 +**总**: 大约 140 行的代码更改,主要集中在现有的类中。 + +## 缓存一致性注意事项 + +**数据时效性权衡:** +- **标签缓存 (5 分钟 TTL)**: 存在提供已删除/重命名的实体标签的风险。 +- **不缓存嵌入**: 不需要 - 嵌入已经针对每个查询进行缓存。 +- **不缓存查询结果**: 防止从已删除实体/关系中获取过时子图结果。 + +**缓解策略:** +- **保守的 TTL 值**: 平衡性能收益(10-20%)与数据新鲜度。 +- **缓存失效钩子**: 可选地集成图 mutation 事件。 +- **监控仪表板**: 跟踪缓存命中率与时效性事件。 +- **可配置的缓存策略**: 允许根据 mutation 频率进行每个部署的调整。 + +**推荐的缓存配置(根据图的 mutation 速率):** +- **高 mutation(每小时 > 100 次更改)**: TTL=60 秒,较小的缓存大小。 +- **中等 mutation(每小时 10-100 次更改)**: TTL=300 秒(默认值)。 +- **低 mutation(每小时 < 10 次更改)**: TTL=600 秒,较大的缓存大小。 + +## 安全注意事项 + +**防止查询注入:** +- 验证所有实体标识符和查询参数。 +- 对所有数据库交互使用参数化查询。 +- 实施查询复杂度限制,以防止拒绝服务攻击。 + +**资源保护:** +- 强制执行最大子图大小限制。 +- 实施查询超时,以防止资源耗尽。 +- 添加内存使用监控和限制。 + +**访问控制:** +- 维护现有的用户和集合隔离。 +- 添加对性能影响操作的审计日志。 +- 实施速率限制,以防止昂贵操作。 + +## 性能注意事项 + +### 预期性能提升 + +**查询减少:** +- 当前:典型的请求大约为 9,000+ 次查询。 +- 优化后:大约 50-100 次批处理查询(减少 98%)。 + +**响应时间改进:** +- 图遍历:15-20 秒 → 3-5 秒(快 4-5 倍)。 +- 标签解析:8-12 秒 → 2-4 秒(快 3 倍)。 +- 总体查询:25-35 秒 → 6-10 秒(提高 3-4 倍)。 + +**内存效率:** +- 边界缓存大小可防止内存泄漏。 +- 高效的数据结构可将内存占用减少 40%。 +- 通过适当的资源清理实现更好的垃圾回收。 + +**可扩展性改进:** +- 支持更大的知识图谱(受缓存一致性需求的限制)。 +- 更高的并发请求容量。 +- 通过连接重用实现更好的资源利用率。 + +### 性能监控 + +**实时指标:** +- 查询执行时间(按操作类型)。 +- 缓存命中率和有效性。 +- 数据库连接池利用率。 +- 内存使用情况和垃圾回收影响。 + +**性能基准测试:** +- 针对当前实现的自动化性能回归测试。 +- 使用真实数据量的负载测试。 +- 针对内存和连接限制进行压力测试。 +- 针对性能改进进行回归测试。 + +## 测试策略 + +### 单元测试 +- 对遍历、缓存和标签解析等各个组件进行测试。 +- 模拟数据库交互以进行性能测试。 +- 缓存淘汰和 TTL 到期测试。 +- 错误处理和超时场景。 + +### 集成测试 +- 使用优化后的 GraphRAG 查询进行端到端测试。 +- 使用真实数据进行数据库交互测试。 +- 并发请求处理和资源管理。 +- 内存泄漏检测和资源清理验证。 + +### 性能测试 +- 针对当前实现进行基准测试。 +- 使用不同大小和复杂度的知识图谱进行负载测试。 +- 针对内存和连接限制进行压力测试。 +- 针对性能改进进行回归测试。 + +### 兼容性测试 +- 验证现有的 GraphRAG API 兼容性。 +- 测试与各种图数据库后端兼容性。 +- 验证与当前实现相比的结果准确性。 + +## 实施计划 + +### 直接实施方法 +由于允许更改 API,因此直接实施优化,而无需迁移的复杂性: + +1. **替换 `follow_edges` 方法**: 使用迭代的批处理遍历进行重写。 +2. **优化 `get_labelgraph`**: 实施并行标签解析。 +3. **添加长期存在的 `GraphRag` 实例**: 修改 `Processor` 以使用持久的实例。 +4. **实施标签缓存**: 在 `GraphRag` 类中添加 LRU 缓存。 + +### 更改范围 +- **`Query` 类**: 替换 `follow_edges` 方法,添加约 30 行批处理处理代码。 +- **`GraphRag` 类**: 添加标签缓存层。 +- **`Processor` 类**: 修改以使用持久的 `GraphRag` 实例,约 20 行代码。 +- **总计**: 大约 140 行的集中代码更改,主要集中在现有的类中。 + +## 时间表 + +**第一周:核心实施** +- 替换 `follow_edges` 方法为批处理迭代遍历。 +- 在 `get_labelgraph` 中实现并行标签解析。 +- 将 `GraphRag` 实例添加到 `Processor`,使其长期存在。 +- 在 `GraphRag` 类中实现标签缓存层。 + +**第二周:测试和集成** +- 对新的遍历和缓存逻辑进行单元测试。 +- 针对当前实现进行性能基准测试。 +- 使用真实图数据进行集成测试。 +- 代码审查和优化。 + +**第三周:部署** +- 部署优化的实现。 +- 监控性能改进。 +- 根据实际使用情况微调缓存 TTL 和批处理大小。 + +## 开放问题 + +- **数据库连接池**: 是否应实施自定义连接池,或依赖于现有的数据库客户端池? +- **缓存持久性**: 是否应跨服务重启持久化标签和嵌入缓存? +- **分布式缓存**: 对于多实例部署,是否应实现分布式缓存(例如,使用 Redis/Memcached)? +- **查询结果格式**: 是否应优化内部三元组表示以实现更好的内存效率? +- **监控集成**: 哪些指标应暴露给现有的监控系统(例如,Prometheus)? + +## 参考资料 + +- [GraphRAG 原始实现](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +- [TrustGraph 架构原则](architecture-principles.md) +- [集合管理规范](collection-management.md) \ No newline at end of file diff --git a/docs/tech-specs/jsonl-prompt-output.ar.md b/docs/tech-specs/jsonl-prompt-output.ar.md new file mode 100644 index 00000000..33808fdc --- /dev/null +++ b/docs/tech-specs/jsonl-prompt-output.ar.md @@ -0,0 +1,74 @@ +# JSONL Prompt Output Technical Specification + +## Overview + +تصف هذه المواصفات تنفيذ تنسيق إخراج JSONL (JSON Lines) لنتائج المطالبات في TrustGraph. يتيح JSONL استخراجًا مقاومًا للتقطيع للبيانات المنظمة من استجابات نماذج اللغة الكبيرة (LLM)، مما يعالج المشكلات الهامة المتعلقة بتلف مخرجات JSON array عندما تصل استجابات نماذج اللغة الكبيرة إلى حدود عدد الرموز المميزة للإخراج. + +تدعم هذه التنفيذ حالات الاستخدام التالية: + +1. **استخراج مقاوم للتقطيع**: استخراج نتائج جزئية صالحة حتى عندما يتم تقطيع إخراج نموذج اللغة الكبيرة في منتصف الاستجابة. +2. **استخراج واسع النطاق**: التعامل مع استخراج العديد من العناصر دون خطر الفشل التام بسبب حدود عدد الرموز المميزة. +3. **استخراج متعدد الأنواع**: دعم استخراج أنواع متعددة من الكيانات (التعريفات، والعلاقات، والكيانات، والسمات) في طلب واحد. +4. **إخراج متوافق مع البث**: تمكين المعالجة المستقبلية للبث/المعالجة التزايدية لنتائج الاستخراج. + +## الأهداف + +* **تحسين مقاومة الأخطاء**: التعامل مع الحالات التي يتم فيها تقطيع استجابات نماذج اللغة الكبيرة. +* **زيادة الكفاءة**: تحسين استخدام الذاكرة في معالجة الاستجابات الكبيرة. +* **تسهيل التوسع**: دعم حالات استخدام أكثر تعقيدًا تتطلب استخراج أنواع متعددة من البيانات. + +## التغييرات + +* إضافة تنسيق إخراج جديد: JSONL +* تعديل طريقة تحليل استجابات نماذج اللغة الكبيرة +* تعديل واجهات برمجة التطبيقات (APIs) لدمج التنسيق الجديد + +## تفاصيل التنفيذ + +### تحليل JSONL + +يتم تحليل استجابات JSONL سطرًا بسطر، مما يسمح باستخراج جزئي حتى في حالة حدوث أخطاء أو تقطيع. + +### مخططات التحقق + +يتم التحقق من صحة كل كائن JSONL بشكل فردي مقابل المخطط المحدد. + +### واجهات برمجة التطبيقات (APIs) + +تظل واجهات برمجة التطبيقات (APIs) ثابتة. لا يلزم إجراء تغييرات على التعليمات البرمجية التي تستهلك النتائج. + +## خطة الترحيل + +1. **تنفيذ**: تنفيذ التحليل والتحقق من صحة JSONL. +2. **ترحيل المطالبات**: ترحيل المطالبات الحالية إلى تنسيق JSONL. +3. **تحديث التعليمات البرمجية**: تحديث التعليمات البرمجية التي تستهلك النتائج للتعامل مع التغييرات. +4. **الاختبار**: إجراء اختبار شامل لضمان التكامل السليم. + +## اعتبارات الأمان + +* تستخدم طريقة التحليل وظيفة `json.loads()` القياسية، وهي آمنة ضد هجمات حقن التعليمات البرمجية. +* تستخدم وظيفة التحقق من المخطط `jsonschema.validate()` لفرض سياسات المخططات. +* لا توجد نقاط ضعف أمنية جديدة تم تقديمها. + +## اعتبارات الأداء + +* يستهلك تحليل JSONL سطرًا بسطر ذاكرة أقل من تحميل مصفوفات JSON بأكملها. +* أداء التحليل مماثل لتحليل مصفوفات JSON. +* يضيف التحقق من المخطط تكلفة إضافية، ولكن يسمح بالنتائج الجزئية في حالة فشل التحقق. + +## استراتيجية الاختبار + +* **اختبارات الوحدة**: اختبار تحليل JSONL، والتحقق من صحة المخططات، والتوافق مع الإصدارات السابقة. +* **اختبارات التكامل**: اختبار سير العمل الشامل، بما في ذلك المحاكاة لتقطيع الاستجابة. +* **اختبارات جودة الاستخراج**: مقارنة نتائج الاستخراج بين تنسيقات JSON ومصفوفات JSON. + +## أسئلة مفتوحة + +لا يوجد أسئلة مفتوحة في الوقت الحالي. + +## المراجع + +* التنفيذ الحالي: `trustgraph-flow/trustgraph/template/prompt_manager.py` +* مواصفات JSON Lines: https://jsonlines.org/ +* مواصفات JSON Schema `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof +* مواصفة ذات صلة: بث استجابات نماذج اللغة الكبيرة (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file diff --git a/docs/tech-specs/jsonl-prompt-output.es.md b/docs/tech-specs/jsonl-prompt-output.es.md new file mode 100644 index 00000000..99fffe19 --- /dev/null +++ b/docs/tech-specs/jsonl-prompt-output.es.md @@ -0,0 +1,75 @@ +# Especificación Técnica de la Salida JSONL para Consultas + +## Resumen + +Esta especificación describe la implementación del formato de salida JSONL (JSON Lines) para las respuestas de las consultas en TrustGraph. JSONL permite la extracción resistente a la truncación de datos estructurados de las respuestas de los LLM (Large Language Models), abordando problemas críticos con las salidas de matrices JSON que se corrompen cuando las respuestas de los LLM alcanzan los límites de tokens de salida. + +Esta implementación admite los siguientes casos de uso: + +1. **Extracción Resistente a la Truncación**: Extrae resultados parciales válidos incluso cuando la salida del LLM se trunca a la mitad de la respuesta. +2. **Extracción a Gran Escala**: Maneja la extracción de muchos elementos sin riesgo de fallo completo debido a los límites de tokens. +3. **Extracción de Tipos Mixtos**: Admite la extracción de múltiples tipos de entidades (definiciones, relaciones, entidades, atributos) en una sola consulta. +4. **Salida Compatible con Transmisión**: Permite el procesamiento futuro de transmisión/incremental de los resultados de la extracción. + +## Objetivos + +- **Compatibilidad Inversa**: Las consultas existentes que utilizan `response-type: "text"` y `response-type: "json"` no se ven afectadas. +- **Flexibilidad**: Permite la extracción de datos estructurados de manera más robusta y eficiente. +- **Mejora de la Experiencia del Usuario**: Proporciona resultados parciales en caso de truncamiento, mejorando la experiencia del usuario. + +## Consideraciones de Diseño + +- **Formato JSONL**: Cada línea de la salida representa un objeto JSON independiente. +- **Resistencia a la Truncación**: La extracción se realiza línea por línea, lo que permite recuperar datos parciales incluso si la respuesta se trunca. +- **Validación de Esquema**: Se valida cada objeto JSON contra un esquema definido para garantizar la calidad de los datos. + +## Cambios en el Código + +- Se introduce un nuevo tipo de respuesta: `response-type: "jsonl"`. +- Se implementa un método de análisis para procesar archivos JSONL línea por línea. +- Se modifica el método de invocación para manejar el nuevo tipo de respuesta y aplicar la validación de esquema. + +## Prompts Afectados + +Los siguientes prompts deben migrarse al formato JSONL: + +| ID del Prompt | Descripción | Campo Tipo | +|---|---|---| +| `extract-definitions` | Extracción de entidades y definiciones | No (tipo único) | +| `extract-relationships` | Extracción de relaciones | No (tipo único) | +| `extract-topics` | Extracción de temas y definiciones | No (tipo único) | +| `extract-rows` | Extracción de filas estructuradas | No (tipo único) | +| `agent-kg-extract` | Extracción combinada de definiciones y relaciones | Sí: `"definition"`, `"relationship"` | +| `extract-with-ontologies` / `ontology-extract` | Extracción basada en ontologías | Sí: `"entity"`, `"relationship"`, `"attribute"` | + +## API + +No se esperan cambios en la API para los clientes. La diferencia es interna en el procesamiento de la respuesta. + +## Estrategia de Pruebas + +- Pruebas unitarias para validar el análisis de JSONL y la gestión de errores. +- Pruebas de integración para verificar el flujo completo de la extracción. +- Pruebas de rendimiento para evaluar el impacto en la latencia y el uso de memoria. + +## Plan de Migración + +1. Implementación de la lógica de análisis JSONL y la gestión del nuevo tipo de respuesta. +2. Migración de los prompts afectados al formato JSONL. +3. Actualización de cualquier código dependiente del formato de salida. + +## Consideraciones de Seguridad + +- El análisis JSONL utiliza las funciones estándar de `json.loads()`, lo que minimiza los riesgos de seguridad. +- La validación de esquema ayuda a garantizar la integridad de los datos. + +## Preguntas Abiertas + +Ninguna en este momento. + +## Referencias + +- Implementación actual: `trustgraph-flow/trustgraph/template/prompt_manager.py` +- Especificación JSON Lines: https://jsonlines.org/ +- JSON Schema `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof +- Especificación relacionada: Transmisión de Respuestas de LLM (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file diff --git a/docs/tech-specs/jsonl-prompt-output.he.md b/docs/tech-specs/jsonl-prompt-output.he.md new file mode 100644 index 00000000..9effc1e6 --- /dev/null +++ b/docs/tech-specs/jsonl-prompt-output.he.md @@ -0,0 +1,51 @@ +# מפרט טכני של פלט JSONL עבור הנחיות + +## סקירה כללית + +מפרט זה מתאר את יישום פורמט הפלט JSONL (JSON Lines) עבור תגובות הנחיות ב-TrustGraph. JSONL מאפשר חילוץ נתונים מובנים מעמידים בסיכויים גבוהים יותר מתגובות של מודלי שפה גדולים (LLM), ומטפל בבעיות קריטיות שמתרחשות כאשר פלטי JSON מערך פגומים כאשר תגובות LLM מגיעות למגבלות של מספר הטוקנים. + +יישום זה תומך בתרחישים הבאים: + +1. **חילוץ עמיד בפני קיטוע:** חילוץ תוצאות חלקיות תקפות גם כאשר פלט LLM מקוטע באמצע התגובה. +2. **חילוץ בקנה מידה גדול:** טיפול בחילוץ של פריטים רבים מבלי להסתכן בכשל מוחלט עקב מגבלות טוקנים. +3. **חילוץ מסוגים מעורבים:** תמיכה בחילוץ סוגים מרובים של ישויות (entities) (הגדרות, קשרים, נושאים וכו') +4. **שיפור ביצועים:** חילוץ יעיל יותר וצריכת זיכרון נמוכה יותר בהשוואה לפורמט JSON מערך. + +### שינויים ב-API + +* **לקוח:** אין שינויים נדרשים בצד הלקוח. לקוחות ממשיכים לקבל רשימה של אובייקטים (list of objects) כפלט, ללא הבדל אם מדובר בפורמט JSON או JSONL. +* **שרת:** שינוי בצד השרת לטובת ניתוח (parsing) של קבצי JSONL שורות-אחר-שורות (line-by-line) כדי לאפשר חילוץ חלקי גם במקרה של קיטוע. + +### תוכנית מעבר + +* **שלב 1: יישום:** יישום פונקציית ניתוח JSONL חדשה בצד השרת. +* **שלב 2: מעבר הנחיות:** מעבר הדרגתי של הנחיות קיימות לפורמט JSONL. +* **שלב 3: עדכונים נלווים:** עדכון קוד צד לקוח (אם יש) כדי להתאים לפורמט הפלט החדש. + +## שיקולי אבטחה + +* **אימות קלט:** ניתוח JSON משתמש בפונקציה `json.loads()` הסטנדרטית, הבטוחה מפני התקפות הזרקה (injection). +* **אימות סכימה:** שימוש ב-`jsonschema.validate()` לאכיפת סכימה. +* **ללא משטח תקיפה חדש:** ניתוח JSONL בטוח יותר מניתוח JSON מערך עקב עיבוד שורות-אחר-שורות. + +## שיקולי ביצועים + +* **זיכרון:** ניתוח שורות-אחר-שורות משתמש בפחות זיכרון שיא בהשוואה לטעינת מערכי JSON שלמים. +* **השהייה:** ביצועי הניתוח דומים לניתוח מערכי JSON. +* **אימות:** אימות סכימה מתבצע עבור כל אובייקט, מה שמוסיף תקורה, אך מאפשר קבלת תוצאות חלקיות גם במקרה של כשל באימות. + +### שיקולים נוספים + +* **אמינות:** פלט JSONL מאפשר המשך עיבוד גם במקרה של שגיאות או קיטועים, בעוד שפלט JSON מערך עלול לגרום לכשל מוחלט. +* **גמישות:** תמיכה בסוגים מעורבים של ישויות (entities) מאפשרת חילוץ נתונים מורכבים יותר. + +## שאלות פתוחות + +אף אחת בשלב זה. + +## הפניות + +* יישום נוכחי: `trustgraph-flow/trustgraph/template/prompt_manager.py` +* מפרט JSON Lines: https://jsonlines.org/ +* סכימת JSON `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof +* מפרט קשור: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file diff --git a/docs/tech-specs/jsonl-prompt-output.hi.md b/docs/tech-specs/jsonl-prompt-output.hi.md new file mode 100644 index 00000000..04ee53f4 --- /dev/null +++ b/docs/tech-specs/jsonl-prompt-output.hi.md @@ -0,0 +1,88 @@ +# JSONL प्रॉम्प्ट आउटपुट तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ में प्रॉम्प्ट प्रतिक्रियाओं के लिए JSONL (JSON लाइन्स) आउटपुट प्रारूप के कार्यान्वयन का वर्णन करता है। JSONL, LLM (लार्ज लैंग्वेज मॉडल) प्रतिक्रियाओं से संरचित डेटा के ट्रंकेशन-प्रतिरोधी निष्कर्षण को सक्षम बनाता है, जो JSON सरणियों के आउटपुट के साथ महत्वपूर्ण समस्याओं को संबोधित करता है जब LLM प्रतिक्रियाएं आउटपुट टोकन सीमाओं तक पहुँच जाती हैं। + +यह कार्यान्वयन निम्नलिखित उपयोग मामलों का समर्थन करता है: + +1. **ट्रंकेशन-प्रतिरोधी निष्कर्षण**: LLM आउटपुट के बीच में काटे जाने पर भी, वैध आंशिक परिणाम निकालें। +2. **बड़े पैमाने पर निष्कर्षण**: टोकन सीमाओं के कारण पूर्ण विफलता के जोखिम के बिना, कई वस्तुओं का निष्कर्षण संभालें। +3. **मिश्रित-प्रकार निष्कर्षण**: एक ही प्रॉम्प्ट में कई इकाई प्रकारों (परिभाषाएं, संबंध, एंटिटीज, विशेषताएँ) का निष्कर्षण समर्थन करें। +4. **स्ट्रीमिंग-संगत आउटपुट**: निष्कर्षण परिणामों की भविष्य की स्ट्रीमिंग/इंक्रीमेंटल प्रोसेसिंग को सक्षम करें। + +## लक्ष्य + +- **पिछला संगतता**: `response-type: "json"` और `response-type: "text"` के साथ मौजूदा प्रॉम्प्ट अपरिवर्तित रहेंगे। +- **आंशिक परिणाम**: ट्रंकेशन के मामले में, आंशिक परिणाम प्राप्त करने की क्षमता। +- **सरल एपीआई**: क्लाइंट-साइड कोड में कोई बदलाव की आवश्यकता नहीं है। + +## सुरक्षा विचार + +- **इनपुट सत्यापन**: JSON पार्सिंग मानक `json.loads()` का उपयोग करता है जो इंजेक्शन हमलों के खिलाफ सुरक्षित है। +- **स्कीमा सत्यापन**: स्कीमा प्रवर्तन के लिए `jsonschema.validate()` का उपयोग किया जाता है। +- **कोई नया हमला सतह नहीं**: JSONL पार्सिंग, पंक्ति-दर-पंक्ति प्रसंस्करण के कारण JSON सरणी पार्सिंग की तुलना में सख्त रूप से सुरक्षित है। + +## प्रदर्शन विचार + +- **मेमोरी**: पंक्ति-दर-पंक्ति पार्सिंग, पूर्ण JSON सरणियों को लोड करने की तुलना में कम पीक मेमोरी का उपयोग करता है। +- **विलंबता**: पार्सिंग प्रदर्शन JSON सरणी पार्सिंग के समान है। +- **सत्यापन**: स्कीमा सत्यापन प्रति-वस्तु चलता है, जो ओवरहेड जोड़ता है लेकिन सत्यापन विफलता पर आंशिक परिणामों को सक्षम करता है। + +## परीक्षण रणनीति + +### यूनिट टेस्ट + +- मान्य इनपुट के साथ JSONL पार्सिंग। +- खाली पंक्तियों के साथ JSONL पार्सिंग। +- Markdown कोड फ़ेंस के साथ JSONL पार्सिंग। +- अंतिम पंक्ति के काटे जाने के साथ JSONL पार्सिंग। +- अमान्य JSON पंक्तियों के साथ JSONL पार्सिंग। +- `oneOf` विभेदक यूनियनों के साथ स्कीमा सत्यापन। +- पिछड़ा संगतता: मौजूदा `"text"` और `"json"` प्रॉम्प्ट अपरिवर्तित। + +### एकीकरण परीक्षण + +- JSONL प्रॉम्प्ट के साथ एंड-टू-एंड निष्कर्षण। +- सिमुलेटेड ट्रंकेशन (कृत्रिम रूप से सीमित प्रतिक्रिया) के साथ निष्कर्षण। +- प्रकार विभेदक के साथ मिश्रित-प्रकार निष्कर्षण। +- सभी तीन प्रकारों के साथ ऑन्टोलॉजी निष्कर्षण। + +### निष्कर्षण गुणवत्ता परीक्षण + +- JSONL बनाम JSON सरणी प्रारूप: निष्कर्षण परिणामों की तुलना। +- ट्रंकेशन प्रतिरोधी: JSONL आंशिक परिणाम देता है जहां JSON विफल रहता है। + +## प्रवासन योजना + +### चरण 1: कार्यान्वयन + +1. `PromptManager` में `parse_jsonl()` विधि लागू करें। +2. `invoke()` का विस्तार `response-type: "jsonl"` को संभालने के लिए। +3. यूनिट टेस्ट जोड़ें। + +### चरण 2: प्रॉम्प्ट प्रवासन + +1. `extract-definitions` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। +2. `extract-relationships` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। +3. `extract-topics` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। +4. `extract-rows` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। +5. `agent-kg-extract` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। +6. `extract-with-ontologies` प्रॉम्प्ट और कॉन्फ़िगरेशन अपडेट करें। + +### चरण 3: डाउनस्ट्रीम अपडेट + +1. निष्कर्षण परिणामों को संभालने के लिए निष्कर्षण परिणामों का उपभोग करने वाले किसी भी कोड को अपडेट करें। +2. `type` फ़ील्ड द्वारा वर्गीकृत मिश्रित-प्रकार निष्कर्षण के लिए कोड को अपडेट करें। +3. निष्कर्षण आउटपुट प्रारूप पर जोर देने वाले परीक्षणों को अपडेट करें। + +## खुले प्रश्न + +इस समय कोई नहीं। + +## संदर्भ + +- वर्तमान कार्यान्वयन: `trustgraph-flow/trustgraph/template/prompt_manager.py` +- JSON लाइन्स विनिर्देश: https://jsonlines.org/ +- JSON स्कीमा `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof +- संबंधित विनिर्देश: स्ट्रीमिंग LLM प्रतिक्रियाएं (`docs/tech-specs/streaming-llm-responses.md`) \ No newline at end of file diff --git a/docs/tech-specs/jsonl-prompt-output.sw.md b/docs/tech-specs/jsonl-prompt-output.sw.md new file mode 100644 index 00000000..24337244 --- /dev/null +++ b/docs/tech-specs/jsonl-prompt-output.sw.md @@ -0,0 +1,618 @@ +# MASHIRIKA YA KIUFUNZI YA TOKEZI YA JSONL + +## Utangulizi + +Mashirika haya yanamaanisha utekelezaji wa umbizo la tokeo la JSONL (JSON Lines) kwa majibu ya ombi katika TrustGraph. JSONL inaruhusu utoaji wa data iliyopangwa kwa ufanisi hata pale ombi linapotokea, ikishughulikia matatizo muhimu ambayo hutokea pale anwani za JSON zinapotokea wakati anwani za LLM zinafikia mipaka ya tokeni. + +Mashirika haya yanaunga mkono matumizi yafuatayo: + +1. **Utoaji wa Matokeo Bila Kukatizwa**: Kuondoa matokeo halali hata pale ombi linapotokea katikati ya jibu. +2. **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa kutokana na mipaka ya tokeni. +3. **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +4. **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mabadiliko Muhimu:** + +* **`response-type`**: Imewekwa kama `"jsonl"`. +* **`schema`**: Imerekebishwa ili kuendana na umbizo la JSONL. +* **`parse_jsonl()`**: Funzione mpya kwa utoaji wa JSONL. + +**Hati muhimu:** + +* **`docs/tech-specs/streaming-llm-responses.md`**: (Uhusiano na utoaji wa anwani) +* **`jsonlines.org`**: (Taarifa kuhusu JSON Lines) +* **`json-schema.org/understanding-json-schema/reference/combining.html#oneof`**: (Maelezo kuhusu "oneOf" katika schema ya JSON) + +**Kumbuka:** + +* Mashirika ya awali yaliyotumia `"json"` yatahitaji marekebisho ili kuendana na umbizo la JSONL. + +**Msisitizo:** + +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa kutokana na mipaka ya tokeni. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mambo Muhimu:** + +* **Urahisi wa Matumizi**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Upeo**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu). +* **Urahisi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Maelezo Mengine:** + +* **`response-type`**: Imewekwa kama `"jsonl"`. +* **`schema`**: Imerekebishwa ili kuendana na umbizo la JSONL. +* **`parse_jsonl()`**: Funzione mpya kwa utoaji wa JSONL. +* **`docs/tech-specs/streaming-llm-responses.md`**: (Uhusiano na utoaji wa anwani) +* **`jsonlines.org`**: (Taarifa kuhusu JSON Lines) +* **`json-schema.org/understanding-json-schema/reference/combining.html#oneof`**: (Maelezo kuhusu "oneOf" katika schema ya JSON) +* **Kumbuka**: Mashirika ya awali yaliyotumia `"json"` yatahitaji marekebisho ili kuendana na umbizo la JSONL. + +**Msisitizo**: Urahisi wa matumizi, upeo, aina mbalimbali, na urahisi. + +**Mambo Muhimu**: Urahisi wa matumizi, upeo, aina mbalimbali, na urahisi. + +**Mchakato wa Utekelezaji**: + +1. **Usanifu**: Utekelezaji wa mashirika na umbizo. +2. **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +3. **Usanifu**: Marekebisho na uboreshaji. +4. **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. + +**Mjadala wa Hatari**: + +* **Utoaji wa Data**: Hakikisha usalama wa data katika utoaji. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Hakikisha usanifu na urahisi wa matumizi. +* **Uchunguzi**: Hakikisha utendakazi na ufanisi wa mashirika. +* **Marekebisho**: Marekebisho na uboreshaji wa mashirika. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji salama na ufanisi wa data. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Ufafanuzi wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Hakikisha urahisi wa matumizi na usanifu. +* **Uchunguzi**: Hakikisha utendakazi na ufanisi wa mashirika. +* **Marekebisho**: Marekebisho na uboreshaji wa mashirika. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Hakikisha urahisi wa matumizi na usanifu. +* **Uchunguzi**: Hakikisha utendakazi na ufanisi wa mashirika. +* **Marekebisho**: Marekebisho na uboreshaji wa mashirika. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Ufafanuzi wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Hakikisha urahisi wa matumizi na usanifu. +* **Uchunguzi**: Hakikisha utendakazi na ufanisi wa mashirika. +* **Marekebisho**: Marekebisho na uboreshaji wa mashirika. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Hakikisha urahisi wa matumizi na usanifu. +* **Uchunguzi**: Hakikisha utendakazi na ufanisi wa mashirika. +* **Marekebisho**: Marekebisho na uboreshaji wa mashirika. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Hakikisha urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Hakikisha urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakazi. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakazi na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakazi na ufanisi wa utoaji wa anwani. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakaji na ufanisi wa utoaji wa anwani. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Hakikisha utendakaji na ufanisi wa utoaji wa anwani. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mada Zinazohusiana**: + +* **Utoaji wa Data**: Utoaji wa data katika mfumo salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Mjadala wa Mada**: + +* **Utoaji wa Data**: Hakikisha usalama na ufanisi wa utoaji wa data. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. + +**Umuhimu wa Mada**: + +* **Utoaji wa Data**: Utoaji wa data salama na ufanisi. +* **Utoaji wa Anwani**: Utoaji wa anwani na utendakaji. +* **Usanifu**: Urahisi wa matumizi na usanifu. +* **Uchunguzi**: Uchunguzi wa utendakaji na ufanisi. +* **Marekebisho**: Marekebisho na uboreshaji. +* **Utoaji**: Utoaji wa mashirika yaliyorekebishwa. +* **Utoaji wa Matokeo Bila Kukatizwa**: Utoaji wa matokeo halali hata pale ombi linapotokea. +* **Utoaji wa Upeo Mkuu**: Kushughulikia uondoaji wa vitu vingi bila hatari ya kushindwa kabisa. +* **Utoaji wa Aina Mbalimbali**: Kusaidia uondoaji wa aina tofauti za vitu (ufafanuzi, uhusiano, vitu, safu) katika ombi moja. +* **Urahisi wa Usanidi**: Urahisi wa usanifu na matengenezo ya mashirika. \ No newline at end of file diff --git a/docs/tech-specs/more-config-cli.hi.md b/docs/tech-specs/more-config-cli.hi.md new file mode 100644 index 00000000..3368352c --- /dev/null +++ b/docs/tech-specs/more-config-cli.hi.md @@ -0,0 +1,195 @@ +```hindi +# अधिक कॉन्फ़िगरेशन CLI तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश TrustGraph के लिए उन्नत कमांड-लाइन कॉन्फ़िगरेशन क्षमताओं का वर्णन करता है, जो उपयोगकर्ताओं को दानेदार CLI कमांड के माध्यम से व्यक्तिगत कॉन्फ़िगरेशन आइटम प्रबंधित करने की अनुमति देता है। यह एकीकरण चार प्राथमिक उपयोग मामलों का समर्थन करता है: + +1. **कॉन्फ़िगरेशन आइटमों की सूची**: किसी विशिष्ट प्रकार की कॉन्फ़िगरेशन कुंजियों का प्रदर्शन करें। +2. **कॉन्फ़िगरेशन आइटम प्राप्त करें**: विशिष्ट कॉन्फ़िगरेशन मान पुनः प्राप्त करें। +3. **कॉन्फ़िगरेशन आइटम सेट करें**: व्यक्तिगत कॉन्फ़िगरेशन आइटम सेट या अपडेट करें। +4. **कॉन्फ़िगरेशन आइटम हटाएं**: विशिष्ट कॉन्फ़िगरेशन आइटम हटाएं। + +## लक्ष्य + +- **बारीक नियंत्रण**: व्यक्तिगत कॉन्फ़िगरेशन आइटमों के प्रबंधन को सक्षम करें, न कि बल्क ऑपरेशनों को। +- **प्रकार-आधारित सूची**: उपयोगकर्ताओं को कॉन्फ़िगरेशन आइटमों को प्रकार के अनुसार ब्राउज़ करने की अनुमति दें। +- **एकल आइटम संचालन**: व्यक्तिगत कॉन्फ़िगरेशन आइटमों के लिए प्राप्त/सेट/हटाने के कमांड प्रदान करें। +- **API एकीकरण**: सभी परिचालनों के लिए मौजूदा कॉन्फ़िगरेशन API का उपयोग करें। +- **संगत CLI पैटर्न**: स्थापित TrustGraph CLI कन्वेंशन और पैटर्न का पालन करें। +- **त्रुटि प्रबंधन**: अमान्य परिचालनों के लिए स्पष्ट त्रुटि संदेश प्रदान करें। +- **JSON आउटपुट**: प्रोग्रामेटिक उपयोग के लिए संरचित आउटपुट का समर्थन करें। +- **प्रलेखन**: व्यापक सहायता और उपयोग उदाहरण शामिल करें। + +## पृष्ठभूमि + +TrustGraph वर्तमान में कॉन्फ़िगरेशन API और एक एकल CLI कमांड `tg-show-config` के माध्यम से कॉन्फ़िगरेशन प्रबंधन प्रदान करता है जो संपूर्ण कॉन्फ़िगरेशन प्रदर्शित करता है। जबकि यह कॉन्फ़िगरेशन देखने के लिए उपयोगी है, यह दानेदार प्रबंधन क्षमताओं की कमी है। + +वर्तमान सीमाएँ शामिल हैं: +- CLI से प्रकार के अनुसार कॉन्फ़िगरेशन आइटमों की सूची बनाने का कोई तरीका नहीं है। +- विशिष्ट कॉन्फ़िगरेशन मान पुनः प्राप्त करने के लिए कोई CLI कमांड नहीं है। +- व्यक्तिगत कॉन्फ़िगरेशन आइटमों को सेट करने के लिए कोई CLI कमांड नहीं है। +- विशिष्ट कॉन्फ़िगरेशन आइटमों को हटाने के लिए कोई CLI कमांड नहीं है। + +यह विनिर्देश इन कमियों को चार नए CLI कमांड जोड़कर संबोधित करता है जो दानेदार कॉन्फ़िगरेशन प्रबंधन प्रदान करते हैं। TrustGraph, CLI कमांड के माध्यम से व्यक्तिगत कॉन्फ़िगरेशन API परिचालनों को उजागर करके: +- स्क्रिप्टेड कॉन्फ़िगरेशन प्रबंधन को सक्षम करें। +- प्रकार के अनुसार कॉन्फ़िगरेशन संरचना की खोज की अनुमति दें। +- लक्षित कॉन्फ़िगरेशन अपडेट का समर्थन करें। +- कॉन्फ़िगरेशन नियंत्रण का महीन स्तर प्रदान करें। + +## तकनीकी डिजाइन + +### आर्किटेक्चर + +उन्नत CLI कॉन्फ़िगरेशन के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: + +1. **tg-list-config-items** + - एक निर्दिष्ट प्रकार के लिए कॉन्फ़िगरेशन कुंजियों की सूची बनाता है। + - `Config.list(type)` API विधि को कॉल करता है। + - कॉन्फ़िगरेशन कुंजियों की सूची आउटपुट करता है। + + मॉड्यूल: `trustgraph.cli.list_config_items` + +2. **tg-get-config-item** + - विशिष्ट कॉन्फ़िगरेशन आइटम(ों) को पुनः प्राप्त करता है। + - `Config.get(keys)` API विधि को कॉल करता है। + - कॉन्फ़िगरेशन मानों को JSON प्रारूप में आउटपुट करता है। + + मॉड्यूल: `trustgraph.cli.get_config_item` + +3. **tg-put-config-item** + - एक कॉन्फ़िगरेशन आइटम सेट या अपडेट करता है। + - `Config.put(values)` API विधि को कॉल करता है। + - प्रकार, कुंजी और मान पैरामीटर स्वीकार करता है। + + मॉड्यूल: `trustgraph.cli.put_config_item` + +4. **tg-delete-config-item** + - एक कॉन्फ़िगरेशन आइटम हटाता है। + - `Config.delete(keys)` API विधि को कॉल करता है। + - प्रकार और कुंजी पैरामीटर स्वीकार करता है। + + मॉड्यूल: `trustgraph.cli.delete_config_item` + +### डेटा मॉडल + +#### ConfigKey और ConfigValue + +कमांड `trustgraph.api.types` से मौजूदा डेटा संरचनाओं का उपयोग करते हैं: + +```python +@dataclasses.dataclass +class ConfigKey: + type : str + key : str + +@dataclasses.dataclass +class ConfigValue: + type : str + key : str + value : str +``` + +यह दृष्टिकोण अनुमति देता है: +- CLI और API में सुसंगत डेटा प्रबंधन। +- प्रकार-सुरक्षित कॉन्फ़िगरेशन संचालन। +- संरचित इनपुट/आउटपुट प्रारूप। +- मौजूदा कॉन्फ़िगरेशन API के साथ एकीकरण। + +### CLI कमांड विनिर्देश + +#### tg-list-config-items +```bash +tg-list-config-items --type [--format text|json] [--api-url ] +``` +- **उद्देश्य**: एक दिए गए प्रकार के सभी कॉन्फ़िगरेशन कुंजियों की सूची बनाएं। +- **API कॉल**: `Config.list(type)` +- **आउटपुट**: + - `text` (डिफ़ॉल्ट): कॉन्फ़िगरेशन कुंजियाँ नई पंक्तियों से अलग की गई हैं। + - `json`: कॉन्फ़िगरेशन कुंजियों की JSON सरणी। + +#### tg-get-config-item +```bash +tg-get-config-item --type --key [--format text|json] [--api-url ] +``` +- **उद्देश्य**: एक विशिष्ट कॉन्फ़िगरेशन आइटम पुनः प्राप्त करें। +- **API कॉल**: `Config.get([ConfigKey(type, key)])` +- **आउटपुट**: + - `text` (डिफ़ॉल्ट): कच्चा स्ट्रिंग मान। + - `json`: JSON-एन्कोडेड स्ट्रिंग मान। + +#### tg-put-config-item +```bash +tg-put-config-item --type --key --value [--api-url ] +tg-put-config-item --type --key --stdin [--api-url ] +``` +- **उद्देश्य**: एक कॉन्फ़िगरेशन आइटम सेट करें। +- **API कॉल**: `Config.put(values)` +- **पैरामीटर**: प्रकार, कुंजी और मान। +- **इनपुट**: कमांड लाइन या stdin के माध्यम से। + +#### tg-delete-config-item +```bash +tg-delete-config-item --type prompt --key old-template +``` +- **उद्देश्य**: एक कॉन्फ़िगरेशन आइटम हटाएं। +- **API कॉल**: `Config.delete(keys)` +- **पैरामीटर**: प्रकार और कुंजी। + +## उपयोग उदाहरण + +#### कॉन्फ़िगरेशन आइटमों की सूची +```bash +# प्रॉम्प्ट कुंजियों की सूची (टेक्स्ट प्रारूप) +tg-list-config-items --type prompt +template-1 +template-2 +system-prompt + +# प्रॉम्प्ट कुंजियों की सूची (JSON प्रारूप) +tg-list-config-items --type prompt --format json +["template-1", "template-2", "system-prompt"] +``` + +#### कॉन्फ़िगरेशन आइटम प्राप्त करें +```bash +# प्रॉम्प्ट मान प्राप्त करें (टेक्स्ट प्रारूप) +tg-get-config-item --type prompt --key template-1 +You are a helpful assistant. Please respond to: {query} + +# प्रॉम्प्ट मान प्राप्त करें (JSON प्रारूप) +tg-get-config-item --type prompt --key template-1 --format json +"You are a helpful assistant. Please respond to: {query}" +``` + +#### कॉन्फ़िगरेशन आइटम सेट करें +```bash +# कमांड लाइन से सेट करें +tg-put-config-item --type prompt --key new-template --value "Custom prompt: {input}" + +# फ़ाइल से पाइप के माध्यम से सेट करें +cat ./prompt-template.txt | tg-put-config-item --type prompt --key complex-template --stdin + +# फ़ाइल से रीडायरेक्ट के माध्यम से सेट करें +tg-put-config-item --type prompt --key complex-template --stdin < ./prompt-template.txt + +# कमांड आउटपुट से सेट करें +echo "Generated template: {query}" | tg-put-config-item --type prompt --key auto-template --stdin +``` + +#### कॉन्फ़िगरेशन आइटम हटाएं +```bash +tg-delete-config-item --type prompt --key old-template +``` + +## खुले प्रश्न + +- क्या कमांड एकल आइटमों के अलावा बैच संचालन (एकाधिक कुंजियाँ) का समर्थन करना चाहिए? +- सफलता की पुष्टि के लिए किस आउटपुट प्रारूप का उपयोग किया जाना चाहिए? +- उपयोगकर्ताओं द्वारा कॉन्फ़िगरेशन प्रकारों का दस्तावेजीकरण/खोज कैसे किया जाना चाहिए? + +## संदर्भ + +- मौजूदा कॉन्फ़िगरेशन API: `trustgraph/api/config.py` +- CLI पैटर्न: `trustgraph-cli/trustgraph/cli/show_config.py` +- डेटा प्रकार: `trustgraph/api/types.py` \ No newline at end of file diff --git a/docs/tech-specs/more-config-cli.sw.md b/docs/tech-specs/more-config-cli.sw.md new file mode 100644 index 00000000..5d0abb91 --- /dev/null +++ b/docs/tech-specs/more-config-cli.sw.md @@ -0,0 +1,197 @@ +# Vipimo vya Zusisi vya Amri ya Utekelezaji (CLI) + +## Muhtasari + +Haya yanaeleza uwezo wa ziada wa usanidi wa amri ya utekelezaji (CLI) kwa TrustGraph, ambayo inaruhusu watumiaji kusimamia vipengele vya usanidi kila kimoja kupitia amri mahususi za CLI. Uunganisho huu unaunga mkono matumizi manne makuu: + +1. **Orodha ya Vipengele vya Usanidi**: Kuonyesha funguo za usanidi za aina fulani. +2. **Pata Kipengele cha Usanidi**: Kuchukua maadili maalum ya usanidi. +3. **Weka Kipengele cha Usanidi**: Kuweka au kusasisha vipengele vya usanidi. +4. **Futa Kipengele cha Usanidi**: Kuondoa vipengele vya usanidi. + +## Malengo + +- **Usimamizi Mahususi**: Kuwezesha usimamizi wa vipengele vya usanidi kila kimoja badala ya shughuli za jumla. +- **Orodha Kulingana na Aina**: Kuruhusu watumiaji kuchunguza vipengele vya usanidi kwa aina. +- **Shughuli za Kipengele Kimoja**: Kutoa amri za kupata/kuweka/kufuta vipengele vya usanidi kila kimoja. +- **Uunganisho wa API**: Kutumia API ya Usanidi iliyopo kwa shughuli zote. +- **Mifumo ya Utekelezaji ya Umoja**: Kufuata misingi na mifumo iliyopo ya CLI ya TrustGraph. +- **Usimamizi wa Makosa**: Kutoa ujumbe wazi wa makosa kwa shughuli zisizo halali. +- **Pato la JSON**: Kusaidia pato lililopangwa kwa matumizi ya programu. +- **Wasifu**: Kuweka msaada kamili na mifano ya matumizi. + +## Licha + +Hivi sasa, TrustGraph hutoa usimamizi wa usanidi kupitia API ya Usanidi na amri moja ya CLI, `tg-show-config`, ambayo inaonyesha usanidi wote. Ingawa hii inafaa kwa kuona usanidi, haitoi uwezo wa usimamizi wa kina. + +Hali ya sasa ya kikwazo ni pamoja na: +- Hakuna njia ya kuorodisha vipengele vya usanidi kwa aina kutoka kwa CLI. +- Hakuna amri ya CLI ya kuchukua maadili maalum ya usanidi. +- Hakuna amri ya CLI ya kuweka vipengele vya usanidi kila kimoja. +- Hakuna amri ya CLI ya kufuta vipengele maalum vya usanidi. + +Haya yanaashiria pengo hili kwa kuongeza amri nne mpya za CLI ambazo hutoa usimamizi wa kina wa usanidi. Kwa kufichua shughuli za API ya Usanidi kupitia amri za CLI, TrustGraph inaweza: +- Kuwezesha usimamizi wa usanidi kwa njia ya programu. +- Kuruhusu kuchunguza muundo wa usanidi kwa aina. +- Kusaidia sasisho maalumu ya usanidi. +- Kutoa udhibiti wa kina wa usanidi. + +## Muundo wa Kiufundi + +### Usanifu + +Utekelezaji wa ziada wa usanidi wa CLI unahitaji vipengele hivi vya kiufundi: + +1. **tg-list-config-items** + - Huorodhesha funguo za usanidi kwa aina iliyoelezwa. + - Huita njia ya API `Config.list(type)`. + - Huonyesha orodha ya funguo za usanidi. + + Moduli: `trustgraph.cli.list_config_items` + +2. **tg-get-config-item** + - Inachukua kipengele(s) maalum(s) cha usanidi. + - Huita njia ya API `Config.get(keys)`. + - Inaonyesha maadili ya usanidi katika umbizo la JSON. + + Moduli: `trustgraph.cli.get_config_item` + +3. **tg-put-config-item** + - Inaweka au kusasisha kipengele cha usanidi. + - Huita njia ya API `Config.put(values)`. + - Inakubali vigezo vya aina, funguo, na thamani. + + Moduli: `trustgraph.cli.put_config_item` + +4. **tg-delete-config-item** + - Inaondoa kipengele cha usanidi. + - Huita njia ya API `Config.delete(keys)`. + - Inakubali vigezo vya aina na funguo. + + Moduli: `trustgraph.cli.delete_config_item` + +### Mifano ya Data + +#### ConfigKey na ConfigValue + +Amri hizi hutumia miundo ya data iliyopo kutoka `trustgraph.api.types`: + +```python +@dataclasses.dataclass +class ConfigKey: + type : string + key : string + +@dataclasses.dataclass +class ConfigValue: + type : string + key : string + value : string +``` + +Mbinu hii inaruhusu: +- Usimamizi wa data thabiti katika CLI na API. +- Shughuli za usanidi salama za aina. +- Umbizo la pembejeo/patou lililopangwa. +- Uunganisho na API ya Usanidi iliyopo. + +### Maelezo ya Amri ya CLI + +#### tg-list-config-items +```bash +tg-list-config-items --type [--format text|json] [--api-url ] +``` +- **Lengo**: Kuorodisha funguo zote za usanidi kwa aina iliyopewa. +- **Wito wa API**: `Config.list(type)` +- **Pato**: + - `text` (cha kawaida): Funguo za usanidi zilizotenganishwa na mistari mipya. + - `json`: Safu ya JSON ya funguo za usanidi. + +#### tg-get-config-item +```bash +tg-get-config-item --type --key [--format text|json] [--api-url ] +``` +- **Lengo**: Kuchukua kipengele maalum cha usanidi. +- **Wito wa API**: `Config.get(keys)` +- **Pato**: + - `text` (cha kawaida): Thamani ya usanidi. + - `json`: Thamani ya usanidi katika umbizo la JSON. + +#### tg-put-config-item +```bash +tg-put-config-item --type --key --value +``` +- **Lengo**: Kuweka thamani ya usanidi. +- **Wito wa API**: `Config.put(values)` +- **Ingizo**: + - `type`: Aina ya usanidi. + - `key`: Funguo ya usanidi. + - `value`: Thamani ya usanidi. + +#### tg-delete-config-item +```bash +tg-delete-config-item --type --key +``` +- **Lengo**: Kuondoa kipengele cha usanidi. +- **Wito wa API**: `Config.delete(keys)` +- **Ingizo**: + - `type`: Aina ya usanidi. + - `key`: Funguo ya usanidi. + +## Mifano ya Matumizi + +#### Kuorodisha vipengele vya usanidi +```bash +# Kuorodisha funguo za prompt (umbizo la maandishi) +tg-list-config-items --type prompt +template-1 +template-2 +system-prompt + +# Kuorodisha funguo za prompt (umbizo la JSON) +tg-list-config-items --type prompt --format json +["template-1", "template-2", "system-prompt"] +``` + +#### Kupata kipengele cha usanidi +```bash +# Kupata thamani ya prompt (umbizo la maandishi) +tg-get-config-item --type prompt --key template-1 +You are a helpful assistant. Please respond to: {query} + +# Kupata thamani ya prompt (umbizo la JSON) +tg-get-config-item --type prompt --key template-1 --format json +"You are a helpful assistant. Please respond to: {query}" +``` + +#### Kuweka kipengele cha usanidi +```bash +# Kuweka kutoka kwa mstari wa amri +tg-put-config-item --type prompt --key new-template --value "Custom prompt: {input}" + +# Kuweka kutoka kwa faili kupitia bomba +cat ./prompt-template.txt | tg-put-config-item --type prompt --key complex-template --stdin + +# Kuweka kutoka kwa faili kupitia urejeshaji +tg-put-config-item --type prompt --key complex-template --stdin < ./prompt-template.txt + +# Kuweka kutoka kwa pato la amri +echo "Generated template: {query}" | tg-put-config-item --type prompt --key auto-template --stdin +``` + +#### Kufuta kipengele cha usanidi +```bash +tg-delete-config-item --type prompt --key old-template +``` + +## Masuala Yaliyoshindikana + +- Je, amri zinapaswa kusaidia shughuli za kundi (funguo nyingi) pamoja na vipengele vya kimoja? +- Umbizo gani la pato unapaswa kutumika kwa uthibitisho wa mafanikio? +- Jinsi aina za usanidi zinavyoweza kuelekezwa/kuchunguzwa na watumiaji? + +## Marejeleo + +- API ya Usanidi iliyopo: `trustgraph/api/config.py` +- Mfumo wa CLI: `trustgraph-cli/trustgraph/cli/show_config.py` +- Data: `trustgraph/api/types.py` \ No newline at end of file diff --git a/docs/tech-specs/neo4j-user-collection-isolation.ar.md b/docs/tech-specs/neo4j-user-collection-isolation.ar.md new file mode 100644 index 00000000..2794dbcf --- /dev/null +++ b/docs/tech-specs/neo4j-user-collection-isolation.ar.md @@ -0,0 +1,190 @@ +# دعم عزل المستخدم/المجموعة في Neo4j + +## بيان المشكلة + +تفتقر آلية تخزين الاستعلامات الثلاثية الحالية في Neo4j إلى عزل المستخدم/المجموعة، مما يؤدي إلى مشكلة أمنية متعددة المستأجرين. يتم تخزين جميع الثلاثيات في نفس مساحة الرسم البياني دون أي آلية لمنع المستخدمين من الوصول إلى بيانات مستخدمين آخرين أو مزج المجموعات. + +على عكس الأنظمة الخلفية الأخرى للتخزين في TrustGraph: +- **Cassandra**: تستخدم مساحات مفاتيح منفصلة لكل مستخدم وجداول لكل مجموعة. +- **مخازن المتجهات** (Milvus, Qdrant, Pinecone): تستخدم مساحات أسماء خاصة بالمجموعة. +- **Neo4j**: تشارك حاليًا جميع البيانات في رسم بياني واحد (ثغرة أمنية). + +## البنية الحالية + +### نموذج البيانات +- **العقد:** تسمية `:Node` مع خاصية `uri`، تسمية `:Literal` مع خاصية `value`. +- **العلاقات:** تسمية `:Rel` مع خاصية `uri`. +- **الفهارس:** `Node.uri`, `Literal.value`, `Rel.uri`. + +### تدفق الرسائل +- تحتوي رسائل `Triples` على الحقول `metadata.user` و `metadata.collection`. +- تتلقى خدمة التخزين معلومات المستخدم/المجموعة ولكنها تتجاهلها. +- تتوقع خدمة الاستعلام `user` و `collection` في `TriplesQueryRequest` ولكنها تتجاهلهما. + +### المشكلة الأمنية الحالية +```cypher +# يمكن لأي مستخدم الاستعلام عن أي بيانات - لا يوجد عزل +MATCH (src:Node)-[rel:Rel]->(dest:Node) +RETURN src.uri, rel.uri, dest.uri +``` + +## الحل المقترح: التصفية المستندة إلى الخصائص (موصى بها) + +### نظرة عامة +إضافة خصائص `user` و `collection` إلى جميع العقد والعلاقات، ثم تصفية جميع العمليات بناءً على هذه الخصائص. يوفر هذا النهج عزلًا قويًا مع الحفاظ على مرونة الاستعلام والتوافق مع الإصدارات السابقة. + +### تغييرات نموذج البيانات + +#### هيكل العقدة المحسّن +```cypher +// كيانات العقد +CREATE (n:Node { + uri: "http://example.com/entity1", + user: "john_doe", + collection: "production_v1" +}) + +// كيانات حرفية +CREATE (n:Literal { + value: "literal value", + user: "john_doe", + collection: "production_v1" +}) +``` + +#### هيكل العلاقة المحسّن +```cypher +// العلاقات مع خصائص المستخدم/المجموعة +CREATE (src)-[:Rel { + uri: "http://example.com/predicate1", + user: "john_doe", + collection: "production_v1" +}]->(dest) +``` + +#### الفهارس المحدثة +```cypher +// فهارس مركبة للتصفية الفعالة +CREATE INDEX node_user_collection_uri FOR (n:Node) ON (n.user, n.collection, n.uri); +CREATE INDEX literal_user_collection_value FOR (n:Literal) ON (n.user, n.collection, n.value); +CREATE INDEX rel_user_collection_uri FOR ()-[r:Rel]-() ON (r.user, r.collection, r.uri); + +// الحفاظ على الفهارس الحالية للتوافق مع الإصدارات السابقة (اختياري) +CREATE INDEX Node_uri FOR (n:Node) ON (n.uri); +CREATE INDEX Literal_value FOR (n:Literal) ON (n.value); +CREATE INDEX Rel_uri FOR ()-[r:Rel]-() ON (r.uri); +``` + +### تنفيذ الخطة + +### المرحلة 1: الأساس (الأسبوع 1) +1. [ ] تحديث خدمة التخزين لقبول وتخزين خصائص المستخدم/المجموعة. +2. [ ] إضافة فهارس مركبة للتصفية الفعالة. +3. [ ] تنفيذ طبقة توافق مع الإصدارات السابقة. +4. [ ] إنشاء اختبارات وحدة للوظائف الجديدة. + +### المرحلة 2: تحديثات الاستعلام (الأسبوع 2) +1. [ ] تحديث جميع أنماط الاستعلام لتشمل عوامل تصفية المستخدم/المجموعة. +2. [ ] إضافة التحقق من صحة الاستعلامات وعناصر التحكم الأمنية. +3. [ ] تحديث اختبارات التكامل. +4. [ ] اختبار الأداء مع الاستعلامات المفلترة. + +### المرحلة 3: الترحيل والنشر (الأسبوع 3) +1. [ ] إنشاء نصوص ترحيل للبيانات لمثيل Neo4j الحالي. +2. [ ] وثائق النشر والتعليمات البرمجية التشغيلية. +3. [ ] المراقبة والتنبيه لانتهاكات العزل. +4. [ ] اختبار شامل مع سيناريوهات متعددة للمستخدمين/المجموعات. + +### المرحلة 4: التقوية (الأسبوع 4) +1. [ ] إزالة وضع التوافق مع الإصدارات القديمة. +2. [ ] إضافة تسجيل تدقيق شامل. +3. [ ] مراجعة أمنية واختبار اختراق. +4. [ ] تحسين الأداء. + +### استراتيجية الاختبار + +### اختبارات الوحدة +```python +def test_user_collection_isolation(): + # تخزين ثلاثيات لمستخدم1/مجموعة1 + processor.store_triples(triples_user1_coll1) + + # تخزين ثلاثيات لمستخدم2/مجموعة2 + processor.store_triples(triples_user2_coll2) + + # يجب أن تعرض الاستعلامات كمستخدم1 فقط بيانات مستخدم1 + results = processor.query_triples(query_user1_coll1) + assert all_results_belong_to_user1_coll1(results) + + # يجب أن تعرض الاستعلامات كمستخدم2 فقط بيانات مستخدم2 + results = processor.query_triples(query_user2_coll2) + assert all_results_belong_to_user2_coll2(results) +``` + +### اختبارات التكامل +- سيناريوهات متعددة المستخدمين مع بيانات متداخلة. +- استعلامات عبر مجموعات (يجب أن تفشل). +- اختبارات الترحيل مع البيانات الحالية. +- معايير أداء مع مجموعات بيانات كبيرة. + +### اختبارات الأمان +- محاولة الاستعلام عن بيانات مستخدمين آخرين. +- هجمات SQL injection على معلمات المستخدم/المجموعة. +- التحقق من العزل الكامل في ظل أنماط استعلام مختلفة. + +### اعتبارات الأداء + +### استراتيجية الفهرس +- فهارس مركبة على `(user, collection, uri)` للتصفية المثلى. +- ضع في اعتبارك الفهارس الجزئية إذا كانت بعض المجموعات أكبر بكثير. +- مراقبة استخدام الفهرس وأداء الاستعلام. + +### تحسين الاستعلام +- استخدم EXPLAIN للتحقق من استخدام الفهرس في الاستعلامات المفلترة. +- ضع في اعتبارك تخزين نتائج الاستعلام مؤقتًا للبيانات التي يتم الوصول إليها بشكل متكرر. +- قم بتوصيف استخدام الذاكرة مع عدد كبير من المستخدمين/المجموعات. + +### قابلية التوسع +- تخلق كل مجموعة مستخدم/مجموعة جزيرة بيانات منفصلة. +- مراقبة حجم قاعدة البيانات واستخدام مجموعة الاتصال. +- ضع في اعتبارك استراتيجيات التوسع الأفقي إذا لزم الأمر. + +### الأمن والامتثال + +### ضمانات العزل +- **الفيزيائية**: جميع بيانات المستخدم مخزنة مع خصائص مستخدم/مجموعة صريحة. +- **المنطقية**: يتم تصفية جميع الاستعلامات بواسطة سياق المستخدم/المجموعة. +- **التحكم في الوصول**: التحقق من الصحة على مستوى الخدمة يمنع الوصول غير المصرح به. + +### متطلبات التدقيق +- تسجيل جميع عمليات الوصول إلى البيانات مع سياق المستخدم/المجموعة. +- تتبع أنشطة الترحيل وحركات البيانات. +- المراقبة بحثًا عن محاولات انتهاك العزل. + +### اعتبارات الامتثال +- GDPR: القدرة المحسنة على تحديد موقع بيانات المستخدم وحذفها. +- SOC2: ضوابط واضحة لعزل المستأجر والوصول. +- HIPAA: عزل قوي للمستأجر لبيانات الرعاية الصحية. + +### المخاطر والتخفيف + +| المخاطر | التأثير | الاحتمالية | التخفيف | +|------|--------|------------|------------| +| الاستعلام المفقود لعامل تصفية المستخدم/المجموعة | مرتفع | متوسط | التحقق الإلزامي، اختبار شامل | +| تدهور الأداء | متوسط | منخفض | تحسين الفهرس، توصيف الاستعلام | +| تلف بيانات الترحيل | مرتفع | منخفض | استراتيجية النسخ الاحتياطي، إجراءات التراجع | +| استعلامات معقدة متعددة المجموعات | متوسط | متوسط | توثيق أنماط الاستعلام، توفير أمثلة | + +### معايير النجاح + +1. **الأمان**: صفر من عمليات الوصول إلى بيانات المستخدم عبر المستخدمين في الإنتاج. +2. **الأداء**: أقل من 10٪ من تأثير أداء الاستعلام مقارنة بالاستعلامات غير المفلترة. +3. **الترحيل**: تم ترحيل 100٪ من البيانات الحالية بنجاح بدون فقدان. +4. **سهولة الاستخدام**: تعمل جميع أنماط الاستعلام الموجودة مع سياق المستخدم/المجموعة. +5. **الامتثال**: سجل تدقيق شامل لعمليات الوصول إلى بيانات المستخدم/المجموعة. + +## الخلاصة + +يوفر النهج القائم على التصفية المستندة إلى الخصائص أفضل توازن بين الأمان والأداء وقابلية الصيانة لإضافة عزل المستخدم/المجموعة إلى Neo4j. إنه يتماشى مع أنماط متعددة المستأجرين الحالية في TrustGraph مع الاستفادة من نقاط قوة Neo4j في استعلامات الرسم البياني والفهرسة. + +تضمن هذه الحل أن يلبي الخلفية Neo4 لـ TrustGraph نفس معايير الأمان مثل الأنظمة الخلفية الأخرى للتخزين، مما يمنع ثغرات أمنية لعزل البيانات مع الحفاظ على المرونة وقوة استعلامات الرسم البياني. \ No newline at end of file diff --git a/docs/tech-specs/neo4j-user-collection-isolation.hi.md b/docs/tech-specs/neo4j-user-collection-isolation.hi.md new file mode 100644 index 00000000..ba248c1a --- /dev/null +++ b/docs/tech-specs/neo4j-user-collection-isolation.hi.md @@ -0,0 +1,134 @@ +# Neo4j उपयोगकर्ता/संग्रह अलगाव समर्थन + +## समस्या विवरण + +Neo4j ट्रिपल भंडारण और क्वेरी कार्यान्वयन में वर्तमान में उपयोगकर्ता/संग्रह अलगाव का अभाव है, जिससे बहु-किरायेदारी सुरक्षा समस्या उत्पन्न होती है। सभी ट्रिपल एक ही ग्राफ स्पेस में संग्रहीत किए जाते हैं, बिना किसी तंत्र के जो उपयोगकर्ताओं को अन्य उपयोगकर्ताओं के डेटा तक पहुंचने या संग्रहों को मिलाने से रोके। + +अन्य ट्रस्टग्राफ स्टोरेज बैकएंड के विपरीत: +- **कैसेंड्रा**: प्रत्येक उपयोगकर्ता के लिए अलग-अलग कीस्पेस और प्रत्येक संग्रह के लिए अलग-अलग टेबल का उपयोग करता है। +- **वेक्टर स्टोर** (मिलवस, क्यूड्रांट, पाइनकोन): संग्रह-विशिष्ट नेमस्पेस का उपयोग करते हैं। +- **Neo4j**: वर्तमान में सभी डेटा को एक ही ग्राफ में साझा करता है (सुरक्षा भेद्यता)। + +## वर्तमान आर्किटेक्चर + +### डेटा मॉडल +- **नोड**: `:Node` लेबल जिसमें `uri` प्रॉपर्टी है, `:Literal` लेबल जिसमें `value` प्रॉपर्टी है। +- **रिलेशनशिप**: `:Rel` लेबल जिसमें `uri` प्रॉपर्टी है। +- **इंडेक्स**: `Node.uri`, `Literal.value`, `Rel.uri` + +### संदेश प्रवाह +- `Triples` संदेशों में `metadata.user` और `metadata.collection` फ़ील्ड होते हैं। +- स्टोरेज सेवा उपयोगकर्ता/संग्रह जानकारी प्राप्त करती है लेकिन उसे अनदेखा करती है। +- क्वेरी सेवा `TriplesQueryRequest` में `user` और `collection` की अपेक्षा करती है लेकिन उन्हें अनदेखा करती है। + +### वर्तमान सुरक्षा समस्या +```cypher +# कोई भी उपयोगकर्ता किसी भी डेटा को क्वेरी कर सकता है - कोई अलगाव नहीं +MATCH (src:Node)-[rel:Rel]->(dest:Node) +RETURN src.uri, rel.uri, dest.uri +``` + +## प्रस्तावित समाधान: प्रॉपर्टी-आधारित फ़िल्टरिंग (अनुशंसित) + +### अवलोकन +सभी नोड्स और रिलेशनशिप में `user` और `collection` प्रॉपर्टी जोड़ें, और फिर सभी ऑपरेशनों को इन प्रॉपर्टीज़ द्वारा फ़िल्टर करें। यह दृष्टिकोण मजबूत अलगाव प्रदान करता है, जबकि क्वेरी लचीलापन और पिछड़े अनुकूलता बनाए रखता है। + +### डेटा मॉडल परिवर्तन + +#### उन्नत नोड संरचना +```cypher +// नोड एंटिटीज +CREATE (n:Node { + uri: "http://example.com/entity1", + user: "john_doe", + collection: "production_v1" +}) + +// लिटरल एंटिटीज +CREATE (n:Literal { + value: "लिटरल वैल्यू", + user: "john_doe", + collection: "production_v1" +}) +``` + +#### उन्नत रिलेशनशिप संरचना +```cypher +// उपयोगकर्ता/संग्रह प्रॉपर्टीज़ के साथ रिलेशनशिप +CREATE (src)-[:Rel { + uri: "http://example.com/predicate1", + user: "john_doe", + collection: "production_v1" +}]->(dest) +``` + +#### अद्यतित इंडेक्स +```cypher +// कुशल फ़िल्टरिंग के लिए कंपाउंड इंडेक्स +CREATE INDEX node_user_collection_uri FOR (n:Node) ON (n.user, n.collection, n.uri); +CREATE INDEX literal_user_collection_value FOR (n:Literal) ON (n.user, n.collection, n.value); +CREATE INDEX rel_user_collection_uri FOR ()-[r:Rel]-() ON (r.user, r.collection, r.uri); + +// पिछड़े अनुकूलता के लिए मौजूदा इंडेक्स बनाए रखें (वैकल्पिक) +CREATE INDEX Node_uri FOR (n:Node) ON (n.uri); +CREATE INDEX Literal_value FOR (n:Literal) ON (n.value); +CREATE INDEX Rel_uri FOR ()-[r:Rel]-() ON (r.uri); +``` + +### कार्यान्वयन परिवर्तन + +#### स्टोरेज सेवा (`write.py`) + +**वर्तमान कोड:** +```python +# (कोड यहां) +``` + +**अद्यतित कोड:** +```python +# (अद्यतित कोड यहां) +``` + +#### क्वेरी सेवा (उदाहरण) +```cypher +# मौजूदा क्वेरी: +MATCH (n:Node) WHERE n.name = 'example' + +# अद्यतित क्वेरी: +MATCH (n:Node) WHERE n.name = 'example' AND n.user = $user AND n.collection = $collection +``` + +### परफॉर्मेंस पर विचार + +- कंपाउंड इंडेक्स का उपयोग करें। +- क्वेरी कैशिंग पर विचार करें। +- डेटा आकार और कनेक्शन पूल उपयोग की निगरानी करें। + +### सुरक्षा और अनुपालन + +- डेटा अलगाव गारंटी +- ऑडिट आवश्यकताएं +- अनुपालन विचार + +### जोखिम और निवारण + +| जोखिम | प्रभाव | संभावना | निवारण | +|------|--------|------------|------------| +| क्वेरी में उपयोगकर्ता/संग्रह फ़िल्टर गायब | उच्च | मध्यम | अनिवार्य सत्यापन, व्यापक परीक्षण | +| परफॉर्मेंस में गिरावट | मध्यम | निम्न | इंडेक्स अनुकूलन, क्वेरी प्रोफाइलिंग | +| माइग्रेशन डेटा भ्रष्टाचार | उच्च | निम्न | बैकअप रणनीति, रोलबैक प्रक्रियाएं | +| जटिल मल्टी-संग्रह क्वेरी | मध्यम | मध्यम | क्वेरी पैटर्न का दस्तावेजीकरण, उदाहरण प्रदान करें | + +### सफलता मानदंड + +1. सुरक्षा: उत्पादन में शून्य क्रॉस-उपयोगकर्ता डेटा एक्सेस +2. परफॉर्मेंस: अनफ़िल्टर किए गए क्वेरी की तुलना में <10% क्वेरी परफॉर्मेंस प्रभाव +3. माइग्रेशन: 100% मौजूदा डेटा बिना किसी नुकसान के सफलतापूर्वक माइग्रेट किया गया +4. उपयोगिता: सभी मौजूदा क्वेरी पैटर्न उपयोगकर्ता/संग्रह संदर्भ के साथ काम करते हैं +5. अनुपालन: उपयोगकर्ता/संग्रह डेटा एक्सेस का पूर्ण ऑडिट ट्रेल + +## निष्कर्ष + +प्रॉपर्टी-आधारित फ़िल्टरिंग दृष्टिकोण Neo4j में उपयोगकर्ता/संग्रह अलगाव जोड़ने के लिए सुरक्षा, परफॉर्मेंस और रखरखाव का सबसे अच्छा संतुलन प्रदान करता है। यह ट्रस्टग्राफ के मौजूदा बहु-किरायेदारी पैटर्न के साथ संरेखित होता है, जबकि ग्राफ क्वेरी और इंडेक्सिंग में Neo4j की ताकत का लाभ उठाता है। + +यह समाधान यह सुनिश्चित करता है कि ट्रस्टग्राफ का Neo4j बैकएंड अन्य स्टोरेज बैकएंड के समान सुरक्षा मानकों को पूरा करे, डेटा अलगाव भेद्यताओं को रोकते हुए ग्राफ क्वेरी की लचीलापन और शक्ति को बनाए रखता है। \ No newline at end of file diff --git a/docs/tech-specs/neo4j-user-collection-isolation.sw.md b/docs/tech-specs/neo4j-user-collection-isolation.sw.md new file mode 100644 index 00000000..51128628 --- /dev/null +++ b/docs/tech-specs/neo4j-user-collection-isolation.sw.md @@ -0,0 +1,184 @@ +# Usaidizi wa Kuhami Mtumiaji/Mkusanyiko katika Neo4j + +## Tatizo + +Hifadhi na utekelezaji wa masuala ya Neo4j kwa sasa hutoi ukinzani wa mtumiaji/mkusanyiko, jambo ambalo huunda tatizo la usalama la utendaji wa wateja wengi. Masuala yote yanahifadhiwa katika nafasi moja ya grafu bila njia yoyote ya kuzuia watumiaji kupata data ya watumiaji wengine au kuchanganya mkusanyiko. + +Tofauti na mifumo mingine ya kuhifadhi katika TrustGraph: +- **Cassandra**: Hutumia nafasi tofauti kwa kila mtumiaji na meza kwa kila mkusanyiko. +- **Hifadhi za Vector** (Milvus, Qdrant, Pinecone): Hutumia nafasi maalum kwa kila mkusanyiko. +- **Neo4j**: Kwa sasa, inashiriki data yote katika grafu moja (hatari ya usalama). + +## Muundo wa Sasa + +### Mfano wa Data +- **Nod**: Laini `:Node` na `uri` ya jambo, `:Literal` na `value` ya jambo. +- **Uhusiano**: Laini `:Rel` na `uri` ya jambo. +- **Faharasa**: `Node.uri`, `Literal.value`, `Rel.uri`. + +### Mzunguko wa Ujumbe +- Ujumbe wa `Triples` una `metadata.user` na `metadata.collection` ya jambo. +- Huduma ya kuhifadhi inapokea taarifa za mtumiaji/mkusanyiko lakini inaizaba. +- Huduma ya kuuliza inatarajia `user` na `collection` katika `TriplesQueryRequest` lakini inaizaba. + +### Tatizo la Sasa la Usalama +```cypher +# Mtumiaji wowote anaweza kuuliza data yoyote - hakuna ukinzani +MATCH (src:Node)-[rel:Rel]->(dest:Node) +RETURN src.uri, rel.uri, dest.uri +``` + +## Suluhisho Lililopendekezwa: Kuchuja Kulingana na Jambo (Inapendekezwa) + +### Muhtasari +Ongeza `user` na `collection` ya jambo kwenye nodi na uhusiano wote, kisha chuja shughuli zote kwa jambo hizi. Njia hii hutoa ukinzani kamili huku ikiendeleza uwezo wa kuuliza na urafiki na mifumo iliyopo. + +### Mabadiliko ya Mfano wa Data + +#### Muundo Ulioboreshwa wa Nodi +```cypher +// Vitu vya Nodi +CREATE (n:Node { + uri: "http://example.com/entity1", + user: "john_doe", + collection: "production_v1" +}) + +// Vitu vya Literal +CREATE (n:Literal { + value: "literal value", + user: "john_doe", + collection: "production_v1" +}) +``` + +#### Muundo Ulioboreshwa wa Uhusiano +```cypher +// Uhusiano na jambo la mtumiaji/mkusanyiko +CREATE (src)-[:Rel { + uri: "http://example.com/predicate1", + user: "john_doe", + collection: "production_v1" +}]->(dest) +``` + +#### Faharasa Zilizosasishwa +```cypher +// Faharasa za pamoja kwa kuchuja kwa ufanisi +CREATE INDEX node_user_collection_uri FOR (n:Node) ON (n.user, n.collection, n.uri); +CREATE INDEX literal_user_collection_value FOR (n:Literal) ON (n.user, n.collection, n.value); +``` + +## Mpango wa Utendaji + +### Awamu ya 1: Msingi (Wiki ya 1) +1. [ ] Sasisha huduma ya kuhifadhi ili kukubali na kuhifadhi jambo la mtumiaji/mkusanyiko. +2. [ ] Ongeza faharasa za pamoja kwa kuuliza kwa ufanisi. +3. [ ] Lenga ukinzani wa nyuma. +4. [ ] Unda vipimo vya kitengo kwa utendakazi mpya. + +### Awamu ya 2: Masuala ya Uulizaji (Wiki ya 2) +1. [ ] Sasisha mifumo yote ya kuuliza ili kujumuisha vichujio vya mtumiaji/mkusanyiko. +2. [ ] Ongeza uthibitisho wa kuuliza na udhibiti wa usalama. +3. [ ] Sasisha vipimo vya ujumuishaji. +4. [ ] Vipimo vya utendaji na masuala yaliyofilishwa. + +### Awamu ya 3: Uhamishaji na Uwekaji (Wiki ya 3) +1. [ ] Unda skripti za uhamishaji wa data kwa matukio ya sasa ya Neo4j. +2. [ ] Nyaraka na maelekezo ya uwekaji. +3. [ ] Ufuatiliaji na arifa kwa ukiukaji wa ukinzani. +4. [ ] Vipimo kamili na matukio mengi ya mtumiaji/mkusanyiko. + +### Awamu ya 4: Uimarishaji (Wiki ya 4) +1. [ ] Ondoa hali ya ukinzani wa nyuma. +2. [ ] Ongeza ufuatiliaji kamili. +3. [ ] Mapitio ya usalama na majaribio ya uvamizi. +4. [ ] Uboreshaji wa utendaji. + +## Mikakati ya Ujaribio + +### Vipimo vya Kitengo +```python +def test_user_collection_isolation(): + # Hifadhi masuala kwa mtumiaji 1/mkusanyiko 1 + processor.store_triples(triples_user1_coll1) + + # Hifadhi masuala kwa mtumiaji 2/mkusanyiko 2 + processor.store_triples(triples_user2_coll2) + + # Uulizaje kama mtumiaji 1 unapaswa kurejesha data ya mtumiaji 1 + results = processor.query_triples(query_user1_coll1) + assert all_results_belong_to_user1_coll1(results) + + # Uulizaje kama mtumiaji 2 unapaswa kurejesha data ya mtumiaji 2 + results = processor.query_triples(query_user2_coll2) + assert all_results_belong_to_user2_coll2(results) +``` + +### Vipimo vya Ujumuishaji +- Matukio mengi ya mtumiaji na data iliyofanana. +- Masuala ya kati ya mkusanyiko (yanapaswa kushindwa). +- Vipimo vya uhamishaji na data iliyopo. +- Benchi za utendaji na data kubwa. + +### Vipimo vya Usalama +- Jaribu kuuliza data ya watumiaji wengine. +- Mashambulio ya aina ya SQL kwenye vigezo vya mtumiaji/mkusanyiko. +- Thibitisha ukinzani kamili chini ya mifumo tofauti ya kuuliza. + +## Masuala ya Utendaji + +### Mkakati wa Faharasa +- Faharasa za pamoja kwenye `(user, collection, uri)` kwa kuchuja bora. +- Fikiria faharasa za sehemu ikiwa baadhi ya makusanyiko ni makubwa sana. +- Fuatilia matumizi ya faharasa na utendaji wa kuuliza. + +### Uboreshaji wa Uulizaji +- Tumia EXPLAIN ili kuhakikisha matumizi ya faharasa katika masuala yaliyofilishwa. +- Fikiria kuhifadhi matokeo ya kuuliza kwa data inayopatikana mara kwa mara. +- Profaili matumizi ya kumbukumbu na idadi kubwa ya watumiaji/makusanyiko. + +### Urahisi +- Kila mtumiaji/mkusanyiko huunda kisiwa cha data. +- Fuatilia saizi ya hifadhi na matumizi ya kikao. +- Fikiria mikakati ya urahisi wa wima ikiwa inahitajika. + +## Usalama na Uzingatiaji + +### Ahadi za Ukinzani wa Data +- **Kimwili**: Data yote ya mtumiaji iliyohifadhiwa na jambo la mtumiaji/mkusanyiko. +- **Mantiki**: Masuala yote yaliyofilishwa kwa muktadha wa mtumiaji/mkusanyiko. +- **Udhibiti wa Ufikiaji**: Uthibitisho wa kiwango cha huduma unaozuia ufikiaji usioidhinishwa. + +### Mahitaji ya Ufuatiliaji +- Ingiza masuala yote ya data na muktadha wa mtumiaji/mkusanyiko. +- Fuatilia shughuli za uhamishaji na uhamishaji wa data. +- Fuatilia majaribio ya ukiukaji wa ukinzani. + +### Masuala ya Uzingatiaji +- GDPR: Uwezo ulioboreshwa wa kutafuta na kufuta data maalum ya mtumiaji. +- SOC2: Ukinzani wa wateja wengi na udhibiti wa ufikiaji. +- HIPAA: Ukinzani wa mteja kwa data ya afya. + +## Hatari na Kupunguza + +| Hatari | Athari | Uwezekano | Kupunguza | +|------|--------|------------|------------| +| Uulizaji unokosa jambo la mtumiaji/mkusanyiko | Juu | Katikati | Uthibitisho wa lazima, vipimo vya kina | +| Uharibifu wa utendaji | Katikati | Chini | Uboreshaji wa faharasa, profaili ya kuuliza | +| Uharibifu wa data ya uhamishaji | Juu | Chini | Mkakati wa chelezo, taratibu za kurejesha | +| Masuala ya kuuliza ya mkusanyiko mingi | Katikati | Katikati | Nyaraka za mifumo ya kuuliza, toa mifano | + +## Vigezo vya Mafanikio + +1. **Usalama**: Hakuna ufikiaji wa data ya mtumiaji mwingine katika uzalishaji. +2. **Utendaji**: <10% athari ya utendaji kwenye masuala yaliyofilishwa. +3. **Uhamishaji**: 100% ya data iliyopo iliyohama bila kupoteza. +4. **Urahisi**: Masuala yote ya sasa ya kuuliza yanapaswa kufanya kazi na muktadha wa mtumiaji/mkusanyiko. +5. **Uzingatiaji**: Ufuatiliaji kamili wa masuala ya mtumiaji/mkusanyiko. + +## Hitimisho + +Njia ya kuchuja kulingana na jambo hutoa uwiano bora wa usalama, utendaji, na urafiki kwa kuongeza ukinzani wa mtumiaji/mkusanyiko katika Neo4j. Inalingana na mifumo iliyopo ya utendaji wa wateja wengi katika TrustGraph huku ikiendeleza nguvu za Neo4j katika kuuliza na faharasa. + +Suluhisho hili huhakikisha kwamba hifadhi ya Neo4j katika TrustGraph inakidhi viwango sawa vya usalama kama mifumo mingine ya kuhifadhi, ikiepuka udhaifu wa ukinzani wa data huku ikiendeleza uwezo na nguvu ya kuuliza ya grafu. \ No newline at end of file diff --git a/docs/tech-specs/ontology.ar.md b/docs/tech-specs/ontology.ar.md new file mode 100644 index 00000000..bf94dc92 --- /dev/null +++ b/docs/tech-specs/ontology.ar.md @@ -0,0 +1,171 @@ +# المواصفات التقنية لهيكل علم الأنطولوجيا + +## نظرة عامة + +تصف هذه المواصفات الهيكل والتنسيق الخاص بعلم الأنطولوجيا داخل نظام TrustGraph. توفر الأنطولوجيا نماذج معرفية رسمية تحدد الفئات والخصائص والعلاقات، مما يدعم قدرات الاستدلال والاستنتاج. يستخدم النظام تنسيقًا مستوحى من OWL، والذي يمثل على نطاق واسع مفاهيم OWL/RDFS، مع تحسينه لتلبية متطلبات TrustGraph. + +**اتفاقية التسمية:** يستخدم هذا المشروع نمط "kebab-case" لجميع المعرفات (مفاتيح التكوين، ونقاط نهاية واجهة برمجة التطبيقات، وأسماء الوحدات، إلخ) بدلاً من نمط "snake_case". + +## الأهداف + +- **إدارة الفئات والخصائص:** تحديد فئات تشبه OWL مع خصائص ومجالات ونطاقات وقيود النوع. +- **دعم دلالي غني:** تمكين خصائص RDFS/OWL شاملة بما في ذلك التسميات ودعم لغات متعددة والقيود الرسمية. +- **دعم أنطولوجيا متعددة:** السماح لعدة أنطولوجيا بالوجود والتفاعل مع بعضها البعض. +- **التحقق والاستدلال:** ضمان توافق الأنطولوجيا مع معايير تشبه OWL مع التحقق من الاتساق ودعم الاستدلال. +- **التوافق مع المعايير:** دعم الاستيراد/التصدير بتنسيقات قياسية (Turtle، RDF/XML، OWL/XML) مع الحفاظ على التحسين الداخلي. + +## الخلفية + +يخزن نظام TrustGraph الأنطولوجيا كعناصر تكوين في نظام مرن من المفاتيح والقيم. على الرغم من أن التنسيق مستوحى من OWL (Web Ontology Language)، إلا أنه مُحسَّن لحالات الاستخدام المحددة لـ TrustGraph ولا يلتزم بشكل صارم بجميع مواصفات OWL. + +تُمكّن الأنطولوجيا في TrustGraph: +- تعريف أنواع الكائنات الرسمية وخصائصها. +- تحديد نطاقات وقيود أنواع الخصائص. +- الاستدلال والاستنتاج المنطقي. +- علاقات معقدة وقيود التعددية. +- دعم لغات متعددة للترجمة. + +## هيكل الأنطولوجيا + +### تخزين التكوين + +يتم تخزين الأنطولوجيا كعناصر تكوين بالنمط التالي: +- **النوع:** `ontology` +- **المفتاح:** معرف الأنطولوجيا الفريد (على سبيل المثال، `natural-world`، `domain-model`). +- **القيمة:** الأنطولوجيا بأكملها بتنسيق JSON. + +### هيكل JSON + +يتكون تنسيق JSON للأنطولوجيا من أربعة أقسام رئيسية: + +#### 1. البيانات الوصفية (Metadata) + +يحتوي على معلومات إدارية ووصفية حول الأنطولوجيا: + +```json +{ + "metadata": { + "name": "العالم الطبيعي", + "description": "أنطولوجيا تغطي النظام الطبيعي", + "version": "1.0.0", + "created": "2025-09-20T12:07:37.068Z", + "modified": "2025-09-20T12:12:20.725Z", + "creator": "current-user", + "namespace": "http://trustgraph.ai/ontologies/natural-world", + "imports": ["http://www.w3.org/2002/07/owl#"] + } +} +``` + +**الحقول:** +- `name`: الاسم القابل للقراءة البشرية للأنطولوجيا. +- `description`: وصف موجز لغرض الأنطولوجيا. +- `version`: رقم الإصدار الدلالي. +- `created`: طابع زمني ISO 8601 للإعداد. +- `modified`: طابع زمني ISO 8601 للتعديل الأخير. +- `creator`: معرف المستخدم/النظام الذي قام بإنشاء الأنطولوجيا. +- `namespace`: عنوان URI الأساسي لعناصر الأنطولوجيا. +- `imports`: مصفوفة من عناوين URI للأنطولوجيا المستوردة. + +#### 2. الفئات (Classes) + +تحدد أنواع الكائنات والعلاقات الهرمية بينها: + +```json +{ + "classes": { + "animal": { + "uri": "http://trustgraph.ai/ontologies/natural-world#animal", + "type": "owl:Class", + "rdfs:label": [{"value": "حيوان", "lang": "en"}], + "rdfs:comment": "حيوان", + "rdfs:subClassOf": "lifeform", + "owl:equivalentClass": ["cat", "dog"], + "owl:disjointWith": ["cat"] + }, + "lifeform": { + "uri": "http://trustgraph.ai/ontologies/natural-world#lifeform", + "type": "owl:Class", + "rdfs:label": [{"value": "كائن حي", "lang": "en"}], + "rdfs:comment": "كائن حي" + }, + "cat": { + "uri": "http://trustgraph.ai/ontologies/natural-world#cat", + "type": "owl:Class", + "rdfs:label": [{"value": "قط", "lang": "en"}], + "rdfs:comment": "قط", + "rdfs:subClassOf": "animal" + }, + "dog": { + "uri": "http://trustgraph.ai/ontologies/natural-world#dog", + "type": "owl:Class", + "rdfs:label": [{"value": "كلب", "lang": "en"}], + "rdfs:comment": "كلب", + "rdfs:subClassOf": "animal", + "owl:disjointWith": ["cat"] + } + } +} +``` + +#### 3. الخصائص (Object Properties) + +تحدد العلاقات بين الفئات: + +```json +{ + "objectProperties": {} +} +``` + +#### 4. خصائص البيانات (Data Properties) + +تحدد الخصائص التي تربط الكائنات ببيانات: + +```json +{ + "datatypeProperties": { + "number-of-legs": { + "uri": "http://trustgraph.ai/ontologies/natural-world#number-of-legs", + "type": "owl:DatatypeProperty", + "rdfs:label": [{"value": "عدد الأرجل", "lang": "en"}], + "rdfs:comment": "عدد أرجل الحيوان", + "rdfs:range": "xsd:nonNegativeInteger", + "rdfs:domain": "animal" + } + } +} +``` + +## قواعد التحقق + +### التحقق الهيكلي + +1. **اتساق URI:** يجب أن تتبع جميع عناوين URI النمط `{namespace}#{identifier}`. +2. **هرمية الفئات:** لا توجد علاقات إرثية دائرية في `rdfs:subClassOf`. +3. **نطاقات وقيود أنواع الخصائص:** يجب أن تشير إلى فئات موجودة أو أنواع XSD صالحة. +4. **فئات متباينة:** لا يمكن أن تكون فئة فرعية من فئة أخرى. +5. **خصائص عكسية:** يجب أن تكون ثنائية الاتجاه إذا تم تحديدها. + +### التحقق الدلالي + +1. **معرفات فريدة:** يجب أن تكون معرّفات الفئات والخصائص فريدة داخل أنطولوجيا واحدة. +2. **علامات اللغة:** يجب أن تتبع تنسيق علامة اللغة BCP 47. +3. **قيود التعددية:** يجب أن يكون `minCardinality` ≤ `maxCardinality` عند تحديد كليهما. +4. **خصائص وظيفية:** لا يمكن أن يكون لها `maxCardinality` > 1. + +## دعم تنسيق الاستيراد/التصدير + +في حين أن التنسيق الداخلي هو JSON، يدعم النظام التحويل إلى/من تنسيقات الأنطولوجيا القياسية: + +- **Turtle (.ttl):** تسلسل RDF مضغوط. +- **RDF/XML (.rdf، .owl):** تنسيق W3C قياسي. +- **OWL/XML (.owx):** تنسيق XML خاص بـ OWL. +- **JSON-LD (.jsonld):** JSON للبيانات المرتبطة. + +## المراجع + +- [OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +- [RDF Schema 1.1](https://www.w3.org/TR/rdf-schema/) +- [XML Schema Datatypes](https://www.w3.org/TR/xmlschema-2/) +- [BCP 47 Language Tags](https://tools.ietf.org/html/bcp47) \ No newline at end of file diff --git a/docs/tech-specs/ontology.es.md b/docs/tech-specs/ontology.es.md new file mode 100644 index 00000000..1346b870 --- /dev/null +++ b/docs/tech-specs/ontology.es.md @@ -0,0 +1,269 @@ +# Especificación Técnica de la Estructura de Ontologías + +## Resumen + +Esta especificación describe la estructura y el formato de las ontologías dentro del sistema TrustGraph. Las ontologías proporcionan modelos de conocimiento formales que definen clases, propiedades y relaciones, lo que permite capacidades de razonamiento e inferencia. El sistema utiliza un formato de configuración inspirado en OWL que representa ampliamente los conceptos de OWL/RDFS, al tiempo que está optimizado para los requisitos de TrustGraph. + +**Convención de Nombres**: Este proyecto utiliza kebab-case para todos los identificadores (claves de configuración, puntos finales de la API, nombres de módulos, etc.) en lugar de snake_case. + +## Objetivos + +- **Gestión de Clases y Propiedades**: Definir clases similares a OWL con propiedades, dominios, rangos y restricciones de tipo. +- **Soporte Semántico Avanzado**: Permitir propiedades completas de RDFS/OWL, incluyendo etiquetas, soporte multilingüe y restricciones formales. +- **Soporte para Múltiples Ontologías**: Permitir que múltiples ontologías coexistan e interactúen. +- **Validación y Razonamiento**: Asegurar que las ontologías cumplan con estándares similares a OWL, con verificación de consistencia y soporte de inferencia. +- **Compatibilidad con Estándares**: Soporte de importación/exportación en formatos estándar (Turtle, RDF/XML, OWL/XML) al tiempo que se mantiene la optimización interna. + +## Antecedentes + +TrustGraph almacena ontologías como elementos de configuración en un sistema flexible de clave-valor. Si bien el formato está inspirado en OWL (Web Ontology Language), está optimizado para los casos de uso específicos de TrustGraph y no se adhiere estrictamente a todas las especificaciones de OWL. + +Las ontologías en TrustGraph permiten: +- Definición de tipos de objetos formales y sus propiedades. +- Especificación de dominios, rangos y restricciones de tipo de propiedades. +- Razonamiento e inferencia lógicos. +- Relaciones complejas y restricciones de cardinalidad. +- Soporte multilingüe para la internacionalización. + +## Estructura de la Ontología + +### Almacenamiento de la Configuración + +Las ontologías se almacenan como elementos de configuración con el siguiente patrón: +- **Tipo**: `ontology` +- **Clave**: Identificador de ontología único (por ejemplo, `natural-world`, `domain-model`). +- **Valor**: Ontología completa en formato JSON. + +### Estructura JSON + +El formato JSON de la ontología consta de cuatro secciones principales: + +#### 1. Metadatos + +Contiene información administrativa y descriptiva sobre la ontología: + +```json +{ + "metadata": { + "name": "The natural world", + "description": "Ontology covering the natural order", + "version": "1.0.0", + "created": "2025-09-20T12:07:37.068Z", + "modified": "2025-09-20T12:12:20.725Z", + "creator": "current-user", + "namespace": "http://trustgraph.ai/ontologies/natural-world", + "imports": ["http://www.w3.org/2002/07/owl#"] + } +} +``` + +**Campos:** +- `name`: Nombre legible por humanos de la ontología. +- `description`: Descripción breve del propósito de la ontología. +- `version`: Número de versión semántico. +- `created`: Marca de tiempo ISO 8601 de creación. +- `modified`: Marca de tiempo ISO 8601 de última modificación. +- `creator`: Identificador del usuario/sistema que creó. +- `namespace`: URI base para elementos de la ontología. +- `imports`: Matriz de URIs de ontologías importadas. + +#### 2. Clases + +Define los tipos de objetos y sus relaciones jerárquicas: + +```json +{ + "classes": { + "animal": { + "uri": "http://trustgraph.ai/ontologies/natural-world#animal", + "type": "owl:Class", + "rdfs:label": [{"value": "Animal", "lang": "en"}], + "rdfs:comment": "An animal", + "rdfs:subClassOf": "lifeform", + "owl:equivalentClass": ["creature"], + "owl:disjointWith": ["plant"], + "dcterms:identifier": "ANI-001" + } + } +} +``` + +**Propiedades soportadas:** +- `uri`: URI completa de la clase. +- `type`: Siempre `"owl:Class"`. +- `rdfs:label`: Matriz de etiquetas con etiquetas de idioma. +- `rdfs:comment`: Descripción de la clase. +- `rdfs:subClassOf`: Identificador de la clase padre (herencia simple). +- `owl:equivalentClass`: Lista de clases equivalentes. +- `owl:disjointWith`: Lista de clases disjuntas. +- `dcterms:identifier`: Identificador de la clase. + +#### 3. Propiedades de Objetos + +Define las relaciones entre las clases: + +```json +{ + "objectProperties": { + "hasPart": { + "uri": "http://trustgraph.ai/ontologies/natural-world#hasPart", + "type": "owl:ObjectProperty", + "rdfs:label": [{"value": "hasPart", "lang": "en"}], + "rdfs:comment": "Represents a part-whole relationship", + "domain": "lifeform", + "range": "lifeform" + } + } +} +``` + +**Propiedades soportadas:** +- `uri`: URI completa de la propiedad de objeto. +- `type`: Siempre `"owl:ObjectProperty"`. +- `rdfs:label`: Matriz de etiquetas con etiquetas de idioma. +- `rdfs:comment`: Descripción de la propiedad de objeto. +- `domain`: Clase de dominio de la propiedad de objeto. +- `range`: Clase de rango de la propiedad de objeto. + +#### 4. Propiedades de Datos + +Define las características de las clases: + +```json +{ + "datatypeProperties": { + "number-of-legs": { + "uri": "http://trustgraph.ai/ontologies/natural-world#number-of-legs", + "type": "owl:DatatypeProperty", + "rdfs:label": [{"value": "number-of-legs", "lang": "en"}], + "rdfs:comment": "Count of number of legs of the animal", + "rdfs:range": "xsd:nonNegativeInteger", + "rdfs:domain": "animal" + } + } +} +``` + +**Propiedades soportadas:** +- `uri`: URI completa de la propiedad de datos. +- `type`: Siempre `"owl:DatatypeProperty"`. +- `rdfs:label`: Matriz de etiquetas con etiquetas de idioma. +- `rdfs:comment`: Descripción de la propiedad de datos. +- `rdfs:range`: Tipo de datos de la propiedad de datos. +- `rdfs:domain`: Clase de dominio de la propiedad de datos. + +### Estructura JSON + +El formato JSON de la ontología consta de cuatro secciones principales: + +#### 1. Metadatos + +Contiene información administrativa y descriptiva sobre la ontología: + +```json +{ + "metadata": { + "name": "The natural world", + "description": "Ontology covering the natural order", + "version": "1.0.0", + "created": "2025-09-20T12:07:37.068Z", + "modified": "2025-09-20T12:12:20.725Z", + "creator": "current-user", + "namespace": "http://trustgraph.ai/ontologies/natural-world", + "imports": ["http://www.w3.org/2002/07/owl#"] + } +} +``` + +**Campos:** +- `name`: Nombre legible por humanos de la ontología. +- `description`: Descripción breve del propósito de la ontología. +- `version`: Número de versión semántico. +- `created`: Marca de tiempo ISO 8601 de creación. +- `modified`: Marca de tiempo ISO 8601 de última modificación. +- `creator`: Identificador del usuario/sistema que creó. +- `namespace`: URI base para elementos de la ontología. +- `imports`: Matriz de URIs de ontologías importadas. + +#### 2. Clases + +Define los tipos de objetos y sus relaciones jerárquicas: + +```json +{ + "classes": { + "lifeform": { + "uri": "http://trustgraph.ai/ontologies/natural-world#lifeform", + "type": "owl:Class", + "rdfs:label": [{"value": "Lifeform", "lang": "en"}], + "rdfs:comment": "A living thing" + }, + "animal": { + "uri": "http://trustgraph.ai/ontologies/natural-world#animal", + "type": "owl:Class", + "rdfs:label": [{"value": "Animal", "lang": "en"}], + "rdfs:comment": "An animal", + "rdfs:subClassOf": "lifeform" + }, + "cat": { + "uri": "http://trustgraph.ai/ontologies/natural-world#cat", + "type": "owl:Class", + "rdfs:label": [{"value": "Cat", "lang": "en"}], + "rdfs:comment": "A cat", + "rdfs:subClassOf": "animal" + }, + "dog": { + "uri": "http://trustgraph.ai/ontologies/natural-world#dog", + "type": "owl:Class", + "rdfs:label": [{"value": "Dog", "lang": "en"}], + "rdfs:comment": "A dog", + "rdfs:subClassOf": "animal", + "owl:disjointWith": ["cat"] + } + }, + "objectProperties": {}, + "datatypeProperties": { + "number-of-legs": { + "uri": "http://trustgraph.ai/ontologies/natural-world#number-of-legs", + "type": "owl:DatatypeProperty", + "rdfs:label": [{"value": "number-of-legs", "lang": "en"}], + "rdfs:comment": "Count of number of legs of the animal", + "rdfs:range": "xsd:nonNegativeInteger", + "rdfs:domain": "animal" + } + } +} +``` + +## Reglas de Validación + +### Validación Estructural + +1. **Consistencia de URI**: Todos los URIs deben seguir el patrón `{namespace}#{identifier}`. +2. **Jerarquía de Clases**: No debe haber herencia circular en `rdfs:subClassOf`. +3. **Dominios/Rangos de Propiedades**: Deben referenciar clases existentes o tipos XSD válidos. +4. **Clases Disjuntas**: No pueden ser subclases entre sí. +5. **Propiedades Inversas**: Deben ser bidireccionales si se especifican. + +### Validación Semántica + +1. **Identificadores Únicos**: Los identificadores de clase y propiedad deben ser únicos dentro de una ontología. +2. **Etiquetas de Idioma**: Deben seguir el formato de etiqueta de idioma BCP 47. +3. **Restricciones de Cardinalidad**: `minCardinality` ≤ `maxCardinality` cuando ambos están especificados. +4. **Propiedades Funcionales**: No pueden tener `maxCardinality` > 1. + +## Soporte de Formato de Importación/Exportación + +Si bien el formato interno es JSON, el sistema admite la conversión a/desde formatos de ontología estándar: + +- **Turtle (.ttl)**: Serialización RDF compacta. +- **RDF/XML (.rdf, .owl)**: Formato estándar de W3C. +- **OWL/XML (.owx)**: Formato XML específico de OWL. +- **JSON-LD (.jsonld)**: JSON para Linked Data. + +## Referencias + +- [OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +- [RDF Schema 1.1](https://www.w3.org/TR/rdf-schema/) +- [XML Schema Datatypes](https://www.w3.org/TR/xmlschema-2/) +- [BCP 47 Language Tags](https://tools.ietf.org/html/bcp47) \ No newline at end of file diff --git a/docs/tech-specs/ontology.hi.md b/docs/tech-specs/ontology.hi.md new file mode 100644 index 00000000..132c3fee --- /dev/null +++ b/docs/tech-specs/ontology.hi.md @@ -0,0 +1,180 @@ +# ऑन्टोलॉजी संरचना तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ सिस्टम के भीतर ऑन्टोलॉजी की संरचना और प्रारूप का वर्णन करता है। ऑन्टोलॉजी औपचारिक ज्ञान मॉडल प्रदान करते हैं जो क्लास, गुण और संबंधों को परिभाषित करते हैं, और तर्क और अनुमान क्षमताओं का समर्थन करते हैं। सिस्टम एक OWL-प्रेरित कॉन्फ़िगरेशन प्रारूप का उपयोग करता है जो व्यापक रूप से OWL/RDFS अवधारणाओं का प्रतिनिधित्व करता है, जबकि ट्रस्टग्राफ की आवश्यकताओं के लिए अनुकूलित है। + +**नामकरण सम्मेलन**: यह परियोजना सभी पहचानकर्ताओं (कॉन्फ़िगरेशन कुंजियों, API एंडपॉइंट, मॉड्यूल नामों, आदि) के लिए "केबब-केस" का उपयोग करती है, न कि "स्नेक_केस" का। + +## लक्ष्य + +- **क्लास और प्रॉपर्टी प्रबंधन**: OWL-जैसी क्लास को प्रॉपर्टी, डोमेन, रेंज और टाइप बाधाओं के साथ परिभाषित करें। +- **समृद्ध शब्दार्थ समर्थन**: व्यापक RDFS/OWL प्रॉपर्टी सहित लेबल, बहु-भाषा समर्थन और औपचारिक बाधाओं को सक्षम करें। +- **बहु-ऑन्टोलॉजी समर्थन**: कई ऑन्टोलॉजी को एक साथ मौजूद रहने और इंटरऑपरेट करने की अनुमति दें। +- **सत्यापन और तर्क**: सुनिश्चित करें कि ऑन्टोलॉजी OWL-जैसी मानकों के अनुरूप हैं, जिसमें स्थिरता जांच और अनुमान समर्थन शामिल है। +- **मानक अनुकूलता**: मानक प्रारूपों (टर्टल, RDF/XML, OWL/XML) में आयात/निर्यात का समर्थन करें, जबकि आंतरिक अनुकूलन बनाए रखें। + +## पृष्ठभूमि + +ट्रस्टग्राफ ऑन्टोलॉजी को एक लचीली कुंजी-मान्य सिस्टम में कॉन्फ़िगरेशन आइटम के रूप में संग्रहीत करता है। जबकि प्रारूप OWL (वेब ऑन्टोलॉजी लैंग्वेज) से प्रेरित है, यह ट्रस्टग्राफ के विशिष्ट उपयोग के मामलों के लिए अनुकूलित है और सभी OWL विनिर्देशों का सख्ती से पालन नहीं करता है। + +ट्रस्टग्राफ में ऑन्टोलॉजी निम्नलिखित को सक्षम करते हैं: +- औपचारिक ऑब्जेक्ट प्रकारों और उनके गुणों की परिभाषा +- प्रॉपर्टी डोमेन, रेंज और टाइप बाधाओं का विनिर्देश +- तार्किक तर्क और अनुमान +- जटिल संबंध और कार्डिनैलिटी बाधाएं +- अंतर्राष्ट्रीयकरण के लिए बहु-भाषा समर्थन + +## ऑन्टोलॉजी संरचना + +### कॉन्फ़िगरेशन भंडारण + +ऑन्टोलॉजी को निम्नलिखित पैटर्न के साथ कॉन्फ़िगरेशन आइटम के रूप में संग्रहीत किया जाता है: +- **टाइप**: `ऑन्टोलॉजी` +- **कुंजी**: अद्वितीय ऑन्टोलॉजी पहचानकर्ता (जैसे, `प्राकृतिक-दुनिया`, `डोमेन-मॉडल`) +- **मान**: JSON प्रारूप में पूरी ऑन्टोलॉजी + +### JSON संरचना + +ऑन्टोलॉजी JSON प्रारूप में चार मुख्य अनुभाग होते हैं: + +#### 1. मेटाडेटा + +ऑन्टोलॉजी के बारे में प्रशासनिक और वर्णनात्मक जानकारी शामिल है: + +```json +{ + "metadata": { + "नाम": "प्राकृतिक दुनिया", + "विवरण": "प्राकृतिक क्रम को कवर करने वाली ऑन्टोलॉजी", + "संस्करण": "1.0.0", + "बनाया गया": "2025-09-20T12:07:37.068Z", + "संशोधित": "2025-09-20T12:12:20.725Z", + "निर्माता": "वर्तमान-उपयोगकर्ता", + "नेमस्पेस": "http://trustgraph.ai/ontologies/natural-world", + "आयात": ["http://www.w3.org/2002/07/owl#"] + } +} +``` + +**फ़ील्ड:** +- `नाम`: ऑन्टोलॉजी का मानव-पठनीय नाम +- `विवरण`: ऑन्टोलॉजी के उद्देश्य का संक्षिप्त विवरण +- `संस्करण`: सिमेंटिक संस्करण संख्या +- `बनाया गया`: निर्माण का ISO 8601 टाइमस्टैम्प +- `संशोधित`: अंतिम संशोधन का ISO 8601 टाइमस्टैम्प +- `निर्माता`: निर्माता उपयोगकर्ता/सिस्टम की पहचान +- `नेमस्पेस`: ऑन्टोलॉजी तत्वों के लिए आधार URI +- `आयात`: आयातित ऑन्टोलॉजी URI का सरणी + +#### 2. क्लास + +ऑब्जेक्ट प्रकार और उनके पदानुक्रमित संबंधों को परिभाषित करता है: + +```json +{ + "क्लास": { + "जानवर": { + "URI": "http://trustgraph.ai/ontologies/natural-world#animal", + "टाइप": "owl:Class", + "rdfs:लेबल": [{"मान": "जानवर", "भाषा": "en"}], + "rdfs:टिप्पणी": "एक जानवर", + "rdfs:उपवर्ग": "जीवनरूप", + "owl:समतुल्यक्लास": ["प्राणी"], + "owl:भिन्न": ["पौधा"], + "dcterms:पहचानकर्ता": "ANI-001" + } + } +} +``` + +**समर्थित प्रॉपर्टी:** +- `URI`: क्लास का पूरा URI +- `टाइप`: `owl:Class` +- `rdfs:लेबल`: क्लास का लेबल +- `rdfs:टिप्पणी`: क्लास का विवरण +- `rdfs:उपवर्ग`: पैरेंट क्लास +- `owl:समतुल्यक्लास`: समान क्लास +- `owl:भिन्न`: अलग क्लास +- `dcterms:पहचानकर्ता`: क्लास का पहचानकर्ता + +#### 3. ऑब्जेक्ट प्रॉपर्टी + +ऑब्जेक्ट और उनके गुणों के बीच संबंधों को परिभाषित करता है: + +```json +{ + "ऑब्जेक्टप्रॉपर्टी": { + "hasPart": { + "URI": "http://trustgraph.ai/ontologies/natural-world#hasPart", + "टाइप": "owl:ObjectProperty", + "rdfs:लेबल": [{"मान": "hasPart", "भाषा": "en"}], + "rdfs:टिप्पणी": "यह दर्शाता है कि एक ऑब्जेक्ट का एक भाग है" + } + } +} +``` + +**समर्थित प्रॉपर्टी:** +- `URI`: प्रॉपर्टी का पूरा URI +- `टाइप`: `owl:ObjectProperty` या `owl:DatatypeProperty` +- `rdfs:लेबल`: प्रॉपर्टी का लेबल +- `rdfs:टिप्पणी`: प्रॉपर्टी का विवरण + +#### 4. डेटाटाइप प्रॉपर्टी + +ऑब्जेक्ट के डेटा मानों को परिभाषित करता है: + +```json +{ + "डेटाटाइप्रॉपर्टी": { + "नंबरऑफलेग्स": { + "URI": "http://trustgraph.ai/ontologies/natural-world#number-of-legs", + "टाइप": "owl:DatatypeProperty", + "rdfs:लेबल": [{"मान": "नंबर-ऑफ-लेग्स", "भाषा": "en"}], + "rdfs:टिप्पणी": "जानवर की पैर की संख्या", + "rdfs:डोमेन": "जानवर" + } + } +} +``` + +**समर्थित प्रॉपर्टी:** +- `URI`: प्रॉपर्टी का पूरा URI +- `टाइप`: `owl:DatatypeProperty` +- `rdfs:लेबल`: प्रॉपर्टी का लेबल +- `rdfs:टिप्पणी`: प्रॉपर्टी का विवरण +- `rdfs:डोमेन`: प्रॉपर्टी का डोमेन + +## सत्यापन नियम + +### संरचनात्मक सत्यापन + +1. **URI संगति**: सभी URI `{नेमस्पेस}#{पहचानकर्ता}` पैटर्न का पालन करना चाहिए। +2. **क्लास पदानुक्रम**: `rdfs:उपवर्ग` में कोई गोलाकार वंश नहीं होना चाहिए। +3. **प्रॉपर्टी डोमेन/रेंज**: मौजूदा क्लास या मान्य XSD प्रकारों को संदर्भित करना चाहिए। +4. **भिन्न वर्ग**: एक दूसरे के उपवर्ग नहीं हो सकते। +5. **उलटा प्रॉपर्टी**: यदि निर्दिष्ट है, तो द्विदिश होना चाहिए। + +### शब्दार्थ सत्यापन + +1. **अद्वितीय पहचानकर्ता**: क्लास और प्रॉपर्टी पहचानकर्ता ऑन्टोलॉजी के भीतर अद्वितीय होने चाहिए। +2. **भाषा टैग**: BCP 47 भाषा टैग प्रारूप का पालन करना चाहिए। +3. **कार्डिनैलिटी बाधाएं**: जब दोनों निर्दिष्ट हों, तो `minCardinality` ≤ `maxCardinality` होना चाहिए। +4. **कार्यात्मक प्रॉपर्टी**: `maxCardinality` > 1 नहीं हो सकता। + +## आयात/निर्यात प्रारूप समर्थन + +जबकि आंतरिक प्रारूप JSON है, सिस्टम मानक ऑन्टोलॉजी प्रारूपों में रूपांतरण का समर्थन करता है: + +- **टर्टल (.ttl)** - कॉम्पैक्ट RDF क्रमबद्धता +- **RDF/XML (.rdf, .owl)** - W3C मानक प्रारूप +- **OWL/XML (.owx)** - OWL-विशिष्ट XML प्रारूप +- **JSON-LD (.jsonld)** - लिंक्ड डेटा के लिए JSON + +## संदर्भ + +- [OWL 2 वेब ऑन्टोलॉजी भाषा](https://www.w3.org/TR/owl2-overview/) +- [RDF स्कीमा 1.1](https://www.w3.org/TR/rdf-schema/) +- [XML स्कीमा डेटाटाइप](https://www.w3.org/TR/xmlschema-2/) +- [BCP 47 भाषा टैग](https://tools.ietf.org/html/bcp47) \ No newline at end of file diff --git a/docs/tech-specs/ontology.sw.md b/docs/tech-specs/ontology.sw.md new file mode 100644 index 00000000..98b14122 --- /dev/null +++ b/docs/tech-specs/ontology.sw.md @@ -0,0 +1,147 @@ +# Mbinu ya Muundo wa Ontolojia + +## Maelezo + +Mazingira haya yanatoa maelezo kuhusu muundo na umbizo wa ontolojia ndani ya mfumo wa TrustGraph. Ontolojia hutoa modeli rasmi za maarifa ambayo inafafanua madarasa, sifa, na uhusiano, na inasaidia uwezo wa utafsiri na utabiri. Mfumo hutumia umbizo unaolingana na OWL (Web Ontology Language) ambao unafafanua dhana za OWL/RDFS, lakini umeboreshwa kwa mahitaji maalum ya TrustGraph. + +**Mikataba ya Majina**: Mradi huu hutumia "kebab-case" kwa kitambulisho chote (funguo za usanidi, sehemu za API, majina ya moduli, n.k.) badala ya "snake_case". + +## Lengo + +- **Usimamizi wa Darasa na Sifa**: Tafsiri madarasa kama vile ya OWL na sifa, vikoa, masafa, na vikwazo vya aina. +- **Usaidizi Kamili wa Semantikia**: Uwezo wa kutumia sifa za RDFS/OWL ikiwa ni pamoja na lebo, usaidizi wa lugha nyingi, na vikwazo rasmi. +- **Usaidizi wa Ontolojia nyingi**: Kuruhusu ontolojia nyingi kuwepo na kufanya kazi pamoja. +- **Uthibitisho na Utabiri**: Hakikisha kuwa ontolojia zinafuata viwango vya aina ya OWL, na hutoa ufuatiliaji wa uthabiti na usaidizi wa utabiri. +- **Ulinganisho na Viwango**: Kusaidia uingizaji na urekebishaji katika umbizo wa kawaida (Turtle, RDF/XML, OWL/XML) wakati unahifadhi uboreshaji wa ndani. + +## Misingi + +TrustGraph huhifadhi ontolojia kama vitu vya usanidi katika mfumo wa thamani-funguo ambao una uwezo wa kubadilika. Ingawa umbizo huu unatokana na OWL (Web Ontology Language), umeboreshwa kwa matumio maalum ya TrustGraph na haufuate vipengele vyote vya OWL. + +Ontolojia katika TrustGraph zinaruhusu: +- Ufafanuzi wa aina rasmi za vitu na sifa zake. +- Ufafanuzi wa vikoa na masafa ya sifa, pamoja na vikwazo vya aina. +- Utabiri na utafsiri wa mantiki. +- Uhusiano tata na vikwazo vya wingi. +- Usaidizi wa lugha nyingi kwa utoaji wa lugha. + +## Muundo wa Ontolojia + +### Uhifadhi wa Usanidi + +Ontolojia huhifadhiwa kama vitu vya usanidi na muundo ufuatao: +- **Aina**: `ontology` +- **Funguo**: Kitambulisho cha kipekee cha ontolojia (k.m., `natural-world`, `domain-model`) +- **Thamani**: Ontolojia kamili katika umbizo la JSON. + +### Muundo wa JSON + +Muundo wa JSON wa ontolojia una sehemu nne kuu: + +#### 1. MetaData + +Inayo habari ya utawala na maelezo kuhusu ontolojia: + +```json +{ + "metadata": { + "name": "Ulimwengu wa asili", + "description": "Ontolojia inayofafanua mazingira ya asili", + "version": "1.0.0", + "created": "2025-09-20T12:07:37.068Z", + "modified": "2025-09-20T12:12:20.725Z", + "creator": "mtumiaji-sasa", + "namespace": "http://trustgraph.ai/ontologies/natural-world", + "imports": ["http://www.w3.org/2002/07/owl#"] + } +} +``` + +**Vifaa:** +- `name`: Jina linaloweza kusomwa na binadamu la ontolojia. +- `description`: Maelezo mafupi ya lengo la ontolojia. +- `version`: Nambari ya toleo. +- `created`: Alama ya muda wa ISO 8601 ya uundaji. +- `modified`: Alama ya muda wa ISO 8601 ya mabadiliko ya mwisho. +- `creator`: Kitambulisho cha mtumiaji/mfumo aliyeuunda. +- `namespace`: URI ya msingi kwa vipengele vya ontolojia. +- `imports`: Orodha ya URI za ontolojia zilizounganishwa. + +#### 2. Madarasa + +Inafafanua aina za vitu na uhusiano wao wa kimfumo: + +```json +{ + "classes": { + "lifeform": { + "uri": "http://trustgraph.ai/ontologies/natural-world#lifeform", + "type": "owl:Class", + "rdfs:label": [{"value": "Lifeform", "lang": "en"}], + "rdfs:comment": "Kiumbe hai" + }, + "animal": { + "uri": "http://trustgraph.ai/ontologies/natural-world#animal", + "type": "owl:Class", + "rdfs:label": [{"value": "Animal", "lang": "en"}], + "rdfs:comment": "Kiumbe cha wanyama", + "rdfs:subClassOf": "lifeform" + }, + "cat": { + "uri": "http://trustgraph.ai/ontologies/natural-world#cat", + "type": "owl:Class", + "rdfs:label": [{"value": "Cat", "lang": "en"}], + "rdfs:comment": "Paka", + "rdfs:subClassOf": "animal" + }, + "dog": { + "uri": "http://trustgraph.ai/ontologies/natural-world#dog", + "type": "owl:Class", + "rdfs:label": [{"value": "Dog", "lang": "en"}], + "rdfs:comment": "Mbwa", + "rdfs:subClassOf": "animal", + "owl:disjointWith": ["cat"] + } + }, +``` + +#### 3. Sifa + +(Tangu hakuna sifa katika mfano, sehemu hii imetolewa) + +#### 4. Ufafanuzi wa Sifa za Data + +(Tangu hakunafafanushwi, sehemu hii imetolewa) + +## Kanuni za Uthibitisho + +### Uthibitisho wa Muundo + +1. **Ulinganifu wa URI**: URI zote zinapaswa kufuata muundo `{namespace}#{identifier}`. +2. **Hieroni ya Darasa**: Hakuna urithi wa mzunguko katika `rdfs:subClassOf`. +3. **Vikoa/Masafa ya Sifa**: Lazima irejee madarasa yaliyopo au aina halali za XSD. +4. **Darasa zisizolingana**: Haiwezi kuwa ndogo za kila mmoja. +5. **Sifa za Kinyume**: Lazima iwe bidirectional ikiwa imeelezwa. + +### Uthibitisho wa Semantikia + +1. **Kitambulisho cha kipekee**: Kitambulisho cha darasa na sifa lazima kiwe kipekee ndani ya ontolojia. +2. **Lebo za Lugha**: Lazima ifuate muundo wa lebo wa BCP 47. +3. **Vikwazo vya Kiasi**: `minCardinality` ≤ `maxCardinality` wakati zote zimetajwa. +4. **Sifa za Kifaa**: Haiwezi kuwa na `maxCardinality` > 1. + +## Usaidizi wa Umbizo wa Uingizaji/Urekebishaji + +Ingawa umbizo la ndani ni JSON, mfumo unaweza kubadilisha hadi/kutoka kwa umbizo wa kawaida wa ontolojia: + +- **Turtle (.ttl)** - Urekebishaji kompakt wa RDF. +- **RDF/XML (.rdf, .owl)** - Umbizo la kawaida la W3C. +- **OWL/XML (.owx)** - Umbizo la XML maalum kwa OWL. +- **JSON-LD (.jsonld)** - JSON kwa Data iliyounganishwa. + +## Marejeleo + +- [OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +- [RDF Schema 1.1](https://www.w3.org/TR/rdf-schema/) +- [XML Schema Datatypes](https://www.w3.org/TR/xmlschema-2/) +- [BCP 47 Language Tags](https://tools.ietf.org/html/bcp47) \ No newline at end of file diff --git a/docs/tech-specs/structured-data-schemas.hi.md b/docs/tech-specs/structured-data-schemas.hi.md new file mode 100644 index 00000000..fc3df5e9 --- /dev/null +++ b/docs/tech-specs/structured-data-schemas.hi.md @@ -0,0 +1,139 @@ +# संरचित डेटा पल्सर स्कीमा परिवर्तन + +## अवलोकन + +`STRUCTURED_DATA.md` विनिर्देश के आधार पर, यह दस्तावेज़ आवश्यक पल्सर स्कीमा परिवर्धन और संशोधन प्रस्तावित करता है ताकि ट्रस्टग्राफ में संरचित डेटा क्षमताओं का समर्थन किया जा सके। + +## आवश्यक स्कीमा परिवर्तन + +### 1. कोर स्कीमा संवर्द्धन + +#### उन्नत फ़ील्ड परिभाषा +`core/primitives.py` में मौजूदा `Field` वर्ग में अतिरिक्त गुण होने चाहिए: + +```python +class Field(Record): + name = String() + type = String() # int, string, long, bool, float, double, timestamp + size = Integer() + primary = Boolean() + description = String() + # नए फ़ील्ड: + required = Boolean() # क्या फ़ील्ड अनिवार्य है + enum_values = Array(String()) # एनम प्रकार के फ़ील्ड के लिए + indexed = Boolean() # क्या फ़ील्ड को अनुक्रमित किया जाना चाहिए +``` + +### 2. नई ज्ञान स्कीमा + +#### 2.1 संरचित डेटा सबमिशन +नई फ़ाइल: `knowledge/structured.py` + +```python +from pulsar.schema import Record, String, Bytes, Map +from ..core.metadata import Metadata + +class StructuredDataSubmission(Record): + metadata = Metadata() + format = String() # "json", "csv", "xml" + schema_name = String() # कॉन्फ़िगरेशन में स्कीमा का संदर्भ + data = Bytes() # संसाधित करने के लिए कच्चा डेटा + options = Map(String()) # प्रारूप-विशिष्ट विकल्प +``` + +### 3. नई सेवा स्कीमा + +#### 3.1 एनएलपी से संरचित क्वेरी सेवा +नई फ़ाइल: `services/nlp_query.py` + +```python +from pulsar.schema import Record, String, Array, Map, Integer, Double +from ..core.primitives import Error + +class NLPToStructuredQueryRequest(Record): + natural_language_query = String() + max_results = Integer() + context_hints = Map(String()) # क्वेरी पीढ़ी के लिए वैकल्पिक संदर्भ + +class NLPToStructuredQueryResponse(Record): + error = Error() + graphql_query = String() # उत्पन्न ग्राफ़क्यूएल क्वेरी + variables = Map(String()) # यदि कोई हो तो ग्राफ़क्यूएल चर + detected_schemas = Array(String()) # कौन सी स्कीमा क्वेरी को लक्षित करती हैं + confidence = Double() +``` + +#### 3.2 संरचित क्वेरी सेवा +नई फ़ाइल: `services/structured_query.py` + +```python +from pulsar.schema import Record, String, Map, Array +from ..core.primitives import Error + +class StructuredQueryRequest(Record): + query = String() # ग्राफ़क्यूएल क्वेरी + variables = Map(String()) # ग्राफ़क्यूएल चर + operation_name = String() # मल्टी-ऑपरेशन दस्तावेजों के लिए वैकल्पिक ऑपरेशन नाम + +class StructuredQueryResponse(Record): + error = Error() + data = String() # JSON-एन्कोडेड ग्राफ़क्यूएल प्रतिक्रिया डेटा + errors = Array(String()) # यदि कोई हो तो ग्राफ़क्यूएल त्रुटियां +``` + +#### 2.2 ऑब्जेक्ट निष्कर्षण आउटपुट +नई फ़ाइल: `knowledge/object.py` + +```python +from pulsar.schema import Record, String, Map, Double +from ..core.metadata import Metadata + +class ExtractedObject(Record): + metadata = Metadata() + schema_name = String() # यह ऑब्जेक्ट किस स्कीमा से संबंधित है + values = Map(String()) # फ़ील्ड नाम -> मान + confidence = Double() + source_span = String() # पाठ का वह भाग जहां ऑब्जेक्ट पाया गया था +``` + +### 4. उन्नत ज्ञान स्कीमा + +#### 4.1 ऑब्जेक्ट एम्बेडिंग संवर्द्धन +संरचित ऑब्जेक्ट एम्बेडिंग को बेहतर ढंग से समर्थन करने के लिए `knowledge/embeddings.py` को अपडेट करें: + +```python +class StructuredObjectEmbedding(Record): + metadata = Metadata() + vectors = Array(Array(Double())) + schema_name = String() + object_id = String() # प्राथमिक कुंजी मान + field_embeddings = Map(Array(Double())) # प्रति-फ़ील्ड एम्बेडिंग +``` + +## एकीकरण बिंदु + +### फ्लो एकीकरण + +इन स्कीमा का उपयोग नए फ्लो मॉड्यूल द्वारा किया जाएगा: +- `trustgraph-flow/trustgraph/decoding/structured` - `StructuredDataSubmission` का उपयोग करता है +- `trustgraph-flow/trustgraph/query/nlp_query/cassandra` - एनएलपी क्वेरी स्कीमा का उपयोग करता है +- `trustgraph-flow/trustgraph/query/objects/cassandra` - संरचित क्वेरी स्कीमा का उपयोग करता है +- `trustgraph-flow/trustgraph/extract/object/row/` - `Chunk` का उपभोग करता है, `ExtractedObject` उत्पन्न करता है +- `trustgraph-flow/trustgraph/storage/objects/cassandra` - `Rows` स्कीमा का उपयोग करता है +- `trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant` - ऑब्जेक्ट एम्बेडिंग स्कीमा का उपयोग करता है + +## कार्यान्वयन नोट्स + +1. **स्कीमा संस्करण:** भविष्य के माइग्रेशन समर्थन के लिए `RowSchema` में एक `version` फ़ील्ड जोड़ने पर विचार करें। +2. **प्रकार प्रणाली:** `Field.type` को सभी कैसेंड्रा मूल प्रकारों का समर्थन करना चाहिए। +3. **बैच ऑपरेशन:** अधिकांश सेवाओं को एकल और बैच दोनों ऑपरेशन का समर्थन करना चाहिए। +4. **त्रुटि प्रबंधन:** सभी नई सेवाओं में सुसंगत त्रुटि रिपोर्टिंग। +5. **पिछड़ा संगतता:** मौजूदा स्कीमा अपरिवर्तित रहते हैं, केवल छोटे फ़ील्ड संवर्द्धन को छोड़कर। + +## अगले कदम + +1. नई संरचना में स्कीमा फ़ाइलें लागू करें। +2. मौजूदा सेवाओं को नए स्कीमा प्रकारों को पहचानने के लिए अपडेट करें। +3. इन स्कीमा का उपयोग करने वाले फ्लो मॉड्यूल लागू करें। +4. नई सेवाओं के लिए गेटवे/रिवर्स-गेटवे एंडपॉइंट बनाएं। +5. स्कीमा सत्यापन के लिए यूनिट परीक्षण बनाएं। \ No newline at end of file diff --git a/docs/tech-specs/universal-decoder.ar.md b/docs/tech-specs/universal-decoder.ar.md new file mode 100644 index 00000000..4974fb9b --- /dev/null +++ b/docs/tech-specs/universal-decoder.ar.md @@ -0,0 +1,411 @@ +# جهاز فك ترميز المستندات الشامل + +## العنوان + +جهاز فك ترميز المستندات الشامل يعمل بواسطة `unstructured` — استيراد أي تنسيق مستند شائع +من خلال خدمة واحدة مع تتبع كامل وتكامل مع أمين المكتبة، وتسجيل مواقع المصدر كبيانات وصفية لـ "رسم بياني للمعرفة" من أجل التتبع التام. + +## المشكلة + +يحتوي "TrustGraph" حاليًا على جهاز فك ترميز خاص بملفات PDF. دعم تنسيقات إضافية (DOCX, XLSX, HTML, Markdown، نص عادي، PPTX، إلخ) يتطلب +إما كتابة جهاز فك ترميز جديد لكل تنسيق أو اعتماد مكتبة استخراج عالمية. لكل تنسيق هيكل مختلف — بعضها يعتمد على الصفحات، وبعضها لا — ويجب أن يسجل سلسلة التتبع أين أصل كل جزء من النص المستخرج في المستند الأصلي. + +## الحل المقترح + +### المكتبة: `unstructured` + +استخدم `unstructured.partition.auto.partition()` التي تكتشف تلقائيًا التنسيق من نوع MIME أو امتداد الملف وتستخرج العناصر المنظمة (العنوان، النص السردي، الجدول، عنصر القائمة، إلخ). تحمل كل عنصر بيانات وصفية بما في ذلك: + +- `page_number` (للتنسيقات القائمة على الصفحات مثل PDF، PPTX) +- `element_id` (فريد لكل عنصر) +- `coordinates` (مربع إحاطة لملفات PDF) +- `text` (محتوى النص المستخرج) +- `category` (نوع العنصر: العنوان، النص السردي، الجدول، إلخ.) + +### أنواع العناصر + +تستخرج `unstructured` أنواع العناصر من المستندات. كل عنصر لديه فئة و بيانات وصفية مرتبطة: + +**عناصر النص:** +- `Title` — عناوين الأقسام +- `NarrativeText` — فقرات النص +- `ListItem` — عناصر القوائم المرقمة/المسردة +- `Header`, `Footer` — رؤوس/تذييلات الصفحات +- `FigureCaption` — تسميات للرسومات/الصور +- `Formula` — تعبيرات رياضية +- `Address`, `EmailAddress` — معلومات الاتصال +- `CodeSnippet` — كتل التعليمات البرمجية (من markdown) + +**الجداول:** +- `Table` — بيانات جدولية منظمة. توفر `unstructured` كلاً من + `element.text` (نص عادي) و `element.metadata.text_as_html` + (علامة HTML `` حتى يتمكن نموذج اللغة الكبيرة من التمييز بين الجداول والنص السردي. + +على سبيل المثال، صفحة تحتوي على عنوان وفقرة وجدول تنتج: + +``` +نظرة عامة مالية + +ارتفعت الإيرادات بنسبة 15٪ على أساس سنوي مدفوعة باعتماد المؤسسات. + + + + + +
الربعالإيراداتالنمو
Q1$12M12%
Q2$14M17%
+``` + +هذا يحافظ على هيكل الجدول من خلال التقطيع وإلى مسار الاستخراج، حيث يمكن لنموذج اللغة الكبيرة استخراج العلاقات مباشرة من الخلايا المنظمة بدلاً من تخمين محاذاة الأعمدة من المسافات. + +### معالجة الصور + +تتم استخراج الصور وتخزينها في أمين المكتبة كأوراق فرعية مع `document_type="image"` ومعرف `urn:image:{uuid}`. إنها تحصل على ثلاثيات تتبع من النوع `tg:Image`، مرتبطة بصفحتها/قسمها الأصلية عبر `prov:wasDerivedFrom`. يتم تسجيل البيانات الوصفية للصورة (الإحداثيات والأبعاد و `element_id`) في التتبع. + +**من المهم للغاية، لا يتم إخراج الصور كإخراج `TextDocument`.** يتم تخزينها فقط — ولا يتم إرسالها إلى وحدة تقسيم (chunker) أو أي مسار لمعالجة النصوص. هذا مقصود: + +1. لا يوجد مسار لمعالجة الصور بعد (دمج نموذج الرؤية هو عمل مستقبلي) +2. إرسال بيانات صورة base64 أو أجزاء من OCR إلى مسار استخراج النص سينتج عنه ثلاثيات KG (رسم بياني للمعرفة) غير صحيحة. + +كما يتم استبعاد الصور من النص المجمع للصفحة/القسم — أي عناصر `Image` يتم تخطيها بصمت عند ربط عناصر النص لصفحة/قسم. يسجل سلسلة التتبع أن الصور موجودة وأين ظهرت في المستند، بحيث يمكن لنموذج معالجة صور مستقبلي التقاطها دون إعادة استيراد المستند. + +#### عمل مستقبلي + +- توجيه الكيانات `tg:Image` إلى نموذج رؤية للوصف أو تفسير المخططات أو استخراج بيانات الرسم البياني. +- تخزين أوصاف الصور كمستندات نصية فرعية يتم إدخالها في مسار التقطيع/الاستخراج القياسي. +- ربط المعرفة المستخرجة بالصور المصدر عبر التتبع. + +### استراتيجيات الأقسام + +بالنسبة للتنسيقات القائمة على الصفحات (PDF، PPTX، XLSX)، يتم تجميع العناصر دائمًا حسب الصفحة/الشريحة/الورقة أولاً. بالنسبة للتنسيقات غير القائمة على الصفحات (DOCX، HTML، Markdown، إلخ)، يحتاج جهاز فك الترميز إلى استراتيجية لتقسيم المستند إلى أقسام. هذا قابل للتكوين في وقت التشغيل عبر `--section-strategy`. + +تعتبر كل استراتيجية وظيفة تجميع على قائمة `unstructured` للعناصر. الإخراج هو قائمة بمجموعات العناصر؛ يظل بقية المسار (تجميع النص وتخزين أمين المكتبة والتتبع وإصدار `TextDocument`) متطابقًا بغض النظر عن الاستراتيجية. + +#### `whole-document` (افتراضي) + +إخراج المستند بأكمله كقسم واحد. اسمح لوحدة تقسيم المستند (chunker) بمعالجة جميع عمليات التقسيم. + +- أبسط نهج، خط أساس جيد +- قد ينتج عنه `TextDocument` كبير جدًا للملفات الكبيرة، ولكن وحدة التقسيم تتعامل مع ذلك +- الأفضل عندما تريد أقصى قدر من السياق لكل قسم + +#### `heading` + +التقسيم عند عناصر العناوين (`Title`). كل قسم هو عنوان وجميع المحتويات حتى العنوان التالي من نفس المستوى أو أعلى. تخلق العناوين المتداخلة أقسامًا متداخلة. + +- ينتج وحدات متماسكة من الناحية الموضوعية +- يعمل بشكل جيد مع المستندات المنظمة (التقارير والكتيبات والمواصفات) +- يوفر لـ LLM الاستخراج سياق العنوان جنبًا إلى جنب مع المحتوى +- يرجع إلى `whole-document` إذا لم يتم العثور على أي عناوين + +#### `element-type` + +التقسيم عند حدوث تغيير كبير في نوع العنصر — على وجه التحديد، ابدأ قسمًا جديدًا في الانتقالات بين النص السردي والجداول. تظل العناصر المتتالية من نفس الفئة العامة (نص، نص، نص أو جدول، جدول) مجمعة. + +- يحافظ على الجداول كأقسام منفصلة +- جيد للمستندات ذات المحتوى المختلط (التقارير مع الجداول البيانية) +- يتم إعطاء الجداول اهتمام استخراج مخصص + +#### `count` + +تجميع عدد ثابت من العناصر لكل قسم. قابلة للتكوين عبر `--section-element-count` (افتراضي: 20). + +- بسيط وقابل للتنبؤ +- لا يحترم هيكل المستند +- مفيد كحل احتياطي أو للتجريب + +#### `size` + +تجميع العناصر حتى يتم الوصول إلى حد الأحرف، ثم ابدأ قسمًا جديدًا. يحترم حدود العناصر — لا يقسم في منتصف العنصر. قابلة للتكوين عبر `--section-max-size` (افتراضي: 4000 حرف). + +- ينتج أقسامًا ذات أحجام تقريبًا موحدة +- يحترم حدود العناصر (على عكس وحدة التقسيم السفلية) +- حل وسط جيد بين التحكم في الهيكل والحجم +- إذا تجاوز عنصر واحد الحد، فإنه يصبح قسمه الخاص + +#### تفاعل مع التنسيق القائم على الصفحة + +بالنسبة للتنسيقات القائمة على الصفحات، يكون تجميع الصفحة هو الأولوية دائمًا. يمكن أن تنطبق استراتيجيات القسم بشكل اختياري *داخل* صفحة إذا كانت كبيرة جدًا (على سبيل المثال، صفحة PDF تحتوي على جدول ضخم)، ويتم التحكم في ذلك بواسطة +`--section-within-pages` (افتراضي: false). عندما يكون `false`، تكون كل صفحة دائمًا قسمًا واحدًا بغض النظر عن الحجم. + +### اكتشاف التنسيق + +يحتاج جهاز فك الترميز إلى معرفة نوع MIME الخاص بالمستند لتمريره إلى `partition()` الخاصة بـ `unstructured`. هناك مساران: + +- **مسار أمين المكتبة** (`document_id` مضبوط): استرداد بيانات وصفية المستند من أمين المكتبة أولاً — وهذا يعطينا `kind` (نوع MIME) + الذي تم تسجيله في وقت الرفع. ثم استرداد محتوى المستند. + مكالمتان لأمين المكتبة، ولكن استرداد البيانات الوصفية خفيف الوزن. +- **المسار المضمن** (التوافق مع الإصدارات السابقة، `data` مضبوط): لا توجد بيانات وصفية + متاحة على الرسالة. استخدم `python-magic` لاكتشاف التنسيق + من بايت المحتوى كحل احتياطي. + +لا توجد تغييرات ضرورية في مخطط `Document` — يقوم أمين المكتبة بالفعل بتخزين نوع MIME. + +### الهندسة المعمارية + +خدمة `universal-decoder` واحدة تقوم بما يلي: + +1. تتلقى رسالة `Document` (مضمنة أو عبر مرجع أمين المكتبة) +2. إذا كان مسار أمين المكتبة: استرداد بيانات وصفية المستند (الحصول على نوع MIME)، ثم + استرداد المحتوى. إذا كان المسار المضمن: اكتشاف التنسيق من بايت المحتوى. +3. تستدعي `partition()` لاستخراج العناصر +4. تجميع العناصر: حسب الصفحة للتنسيقات القائمة على الصفحات، حسب استراتيجية القسم المحددة للتنسيقات غير القائمة على الصفحات +5. لكل صفحة/قسم: + - توليد معرف `urn:page:{uuid}` أو `urn:section:{uuid}` + - تجميع نص الصفحة: النص العادي، والجداول كـ HTML، + الصور يتم تخطيها + - حساب إزاحة الأحرف لكل عنصر داخل نص الصفحة + - حفظ في أمين المكتبة كوثيقة فرعية + - حساب ثلاثيات تتبع مع بيانات وصفية موضعية + - إرسال `TextDocument` إلى وحدة تقسيم (chunker) +6. لكل عنصر صورة: + - توليد معرف `urn:image:{uuid}` + - حفظ بيانات الصورة في أمين المكتبة كوثيقة فرعية + - حساب ثلاثيات تتبع (مخزنة فقط، ولا يتم إرسالها إلى وحدة تقسيم) + +### معالجة التنسيقات + +| التنسيق | نوع MIME | قائم على الصفحات | ملاحظات | +|---|---|---|---| +| PDF | application/pdf | نعم | تجميع حسب الصفحة | +| DOCX | application/vnd.openxmlformats... | لا | يستخدم استراتيجية القسم | +| PPTX | application/vnd.openxmlformats... | نعم | تجميع حسب الشريحة | +| XLSX/XLS | application/vnd.openxmlformats... | نعم | تجميع حسب ورقة العمل | +| HTML | text/html | لا | يستخدم استراتيجية القسم | +| Markdown | text/markdown | لا | يستخدم استراتيجية القسم | +| Plain | text/plain | لا | يستخدم استراتيجية القسم | +| CSV | text/csv | لا | يستخدم استراتيجية القسم | +| RST | text/x-rst | لا | يستخدم استراتيجية القسم | +| RTF | application/rtf | لا | يستخدم استراتيجية القسم | +| ODT | application/vnd.oasis... | لا | يستخدم استراتيجية القسم | +| TSV | text/tab-separated-values | لا | يستخدم استراتيجية القسم | + +### بيانات التتبع + +تسجل كل صفحة/قسم كيان بيانات وصفية موضعية على شكل ثلاثيات تتبع في الرسم البياني المصدر (`GRAPH_SOURCE`)، مما يتيح التتبع التام من ثلاثيات KG (رسم بياني للمعرفة) إلى مواضع المستند المصدر. + +#### الحقول الحالية (موجودة بالفعل في `provenance/triples.py`) + +- `page_number` — رقم الصفحة/الورقة/الشريحة (مرقم 1، فقط للتنسيقات القائمة على الصفحات) +- `char_offset` — إزاحة الحرف لهذه الصفحة/القسم داخل نص المستند بالكامل +- `char_length` — طول الحرف لنص هذه الصفحة/القسم + +#### حقول جديدة (قم بتوسيع `provenance/triples.py`) + +- `mime_type` — تنسيق المستند الأصلي (على سبيل المثال، `application/pdf`) +- `element_types` — قائمة `unstructured` لفئات العناصر الموجودة في هذه الصفحة/القسم (على سبيل المثال، "العنوان،النص السردي،الجدول") +- `table_count` — عدد الجداول في هذه الصفحة/القسم +- `image_count` — عدد الصور في هذه الصفحة/القسم + +يتطلب هذا بناء جملة جديد لأسماء النطاقات: + +``` +TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section" +TG_IMAGE_TYPE = "https://trustgraph.ai/ns/Image" +TG_ELEMENT_TYPES = "https://trustgraph.ai/ns/elementTypes" +TG_TABLE_COUNT = "https://trustgraph.ai/ns/tableCount" +TG_IMAGE_COUNT = "https://trustgraph.ai/ns/imageCount" +``` + +مخطط URN للصورة: `urn:image:{uuid}` + +(`TG_MIME_TYPE` موجود بالفعل.) + +#### نوع الكيان الجديد + +بالنسبة للتنسيقات غير القائمة على الصفحات (DOCX، HTML، Markdown، إلخ) حيث يقوم جهاز فك الترميز بإخراج المستند بأكمله كقسم واحد بدلاً من التقسيم حسب الصفحة، يحصل الكيان على نوع جديد: + +``` +TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section" +``` + +هذا يميز الأقسام عن الصفحات عند الاستعلام عن التتبع: + +| الكيان | النوع | متى يتم استخدامه | +|---|---|---| +| Document | `tg:Document` | الملف الذي تم رفعه أصلاً | +| Page | `tg:Page` | تنسيقات قائمة على الصفحات (PDF، PPTX، XLSX) | +| Section | `tg:Section` | تنسيقات غير قائمة على الصفحات (DOCX، HTML، MD، إلخ) | +| Image | `tg:Image` | صور مضمنة (مخزنة، وغير معالجة) | +| Chunk | `tg:Chunk` | إخراج وحدة تقسيم المستند | +| Subgraph | `tg:Subgraph` | إخراج KG | + +يتم تعيين النوع بواسطة جهاز فك الترميز بناءً على ما إذا كان يقوم بتجميع حسب الصفحة أم أنه يصدر قسمًا كاملاً للمستند. تكتسب `provenance/triples.py` معلمة اختيارية `section` — عندما تكون `true`، يتم تصنيف الكيان على أنه `tg:Section` بدلاً من `tg:Page`. + +#### سلسلة التتبع الكاملة + +``` +ثلاثية KG + → subgraph (تتبع الاستخراج) + → chunk (char_offset، char_length داخل الصفحة) + → page/section (page_number، char_offset، char_length داخل المستند، mime_type، element_types) + → document (الملف الأصلي في أمين المكتبة) +``` + +كل رابط هو مجموعة من الثلاثيات في الرسم البياني المسمى `GRAPH_SOURCE`. + +### تكوين الخدمة + +وسيطات سطر الأوامر: + +``` +--strategy استراتيجية التقسيم: auto, hi_res, fast (افتراضي: auto) +--languages قائمة مفصولة بفواصل برموز لغة OCR (افتراضي: eng) +--section-strategy استراتيجية تجميع القسم: whole-document, heading, element-type, + count, size (افتراضي: whole-document) +--section-element-count عدد العناصر لكل قسم (افتراضي: 20) +--section-max-size الحد الأقصى لحجم القسم (بالأحرف) (افتراضي: 4000) +``` + +### التنفيذ + +خدمة `universal-decoder` واحدة تقوم بما يلي: + +1. تتلقى رسالة `Document` (مضمنة أو عبر مرجع أمين المكتبة) +2. إذا كان مسار أمين المكتبة: استرداد بيانات وصفية المستند (الحصول على نوع MIME)، ثم + استرداد المحتوى. إذا كان المسار المضمن: اكتشاف التنسيق من بايت المحتوى. +3. تستدعي `partition()` لاستخراج العناصر +4. تجميع العناصر: حسب الصفحة للتنسيقات القائمة على الصفحات، حسب استراتيجية القسم المحددة للتنسيقات غير القائمة على الصفحات +5. لكل صفحة/قسم: + - توليد معرف `urn:page:{uuid}` أو `urn:section:{uuid}` + - تجميع نص الصفحة: النص العادي، والجداول كـ HTML، + الصور يتم تخطيها + - حساب إزاحة الأحرف لكل عنصر داخل نص الصفحة + - حفظ في أمين المكتبة كوثيقة فرعية + - حساب ثلاثيات تتبع مع بيانات وصفية موضعية + - إرسال `TextDocument` إلى وحدة تقسيم (chunker) +6. لكل عنصر صورة: + - توليد معرف `urn:image:{uuid}` + - حفظ بيانات الصورة في أمين المكتبة كوثيقة فرعية + - حساب ثلاثيات تتبع (مخزنة فقط، ولا يتم إرسالها إلى وحدة تقسيم) + +### معالجة التنسيقات + +| التنسيق | نوع MIME | قائم على الصفحات | ملاحظات | +|---|---|---|---| +| PDF | application/pdf | نعم | تجميع حسب الصفحة | +| DOCX | application/vnd.openxmlformats... | لا | يستخدم استراتيجية القسم | +| PPTX | application/vnd.openxmlformats... | نعم | تجميع حسب الشريحة | +| XLSX/XLS | application/vnd.openxmlformats... | نعم | تجميع حسب ورقة العمل | +| HTML | text/html | لا | يستخدم استراتيجية القسم | +| Markdown | text/markdown | لا | يستخدم استراتيجية القسم | +| Plain | text/plain | لا | يستخدم استراتيجية القسم | +| CSV | text/csv | لا | يستخدم استراتيجية القسم | +| RST | text/x-rst | لا | يستخدم استراتيجية القسم | +| RTF | application/rtf | لا | يستخدم استراتيجية القسم | +| ODT | application/vnd.oasis... | لا | يستخدم استراتيجية القسم | +| TSV | text/tab-separated-values | لا | يستخدم استراتيجية القسم | + +### بيانات التتبع + +تسجل كل صفحة/قسم كيان بيانات وصفية موضعية على شكل ثلاثيات تتبع في الرسم البياني المصدر (`GRAPH_SOURCE`)، مما يتيح التتبع التام من ثلاثيات KG (رسم بياني للمعرفة) إلى مواضع المستند المصدر. + +#### الحقول الحالية (موجودة بالفعل في `provenance/triples.py`) + +- `page_number` — رقم الصفحة/الورقة/الشريحة (مرقم 1، فقط للتنسيقات القائمة على الصفحات) +- `char_offset` — إزاحة الحرف لهذه الصفحة/القسم داخل نص المستند بالكامل +- `char_length` — طول الحرف لنص هذه الصفحة/القسم + +#### حقول جديدة (قم بتوسيع `provenance/triples.py`) + +- `mime_type` — تنسيق المستند الأصلي (على سبيل المثال، `application/pdf`) +- `element_types` — قائمة `unstructured` لفئات العناصر الموجودة في هذه الصفحة/القسم (على سبيل المثال، "العنوان،النص السردي،الجدول") +- `table_count` — عدد الجداول في هذه الصفحة/القسم +- `image_count` — عدد الصور في هذه الصفحة/القسم + +يتطلب هذا بناء جملة جديد لأسماء النطاقات: + +``` +TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section" +TG_IMAGE_TYPE = "https://trustgraph.ai/ns/Image" +TG_ELEMENT_TYPES = "https://trustgraph.ai/ns/elementTypes" +TG_TABLE_COUNT = "https://trustgraph.ai/ns/tableCount" +TG_IMAGE_COUNT = "https://trustgraph.ai/ns/imageCount" +``` + +مخطط URN للصورة: `urn:image:{uuid}` + +(`TG_MIME_TYPE` موجود بالفعل.) + +#### نوع الكيان الجديد + +بالنسبة للتنسيقات غير القائمة على الصفحات (DOCX، HTML، Markdown، إلخ) حيث يقوم جهاز فك الترميز بإخراج المستند بأكمله كقسم واحد بدلاً من التقسيم حسب الصفحة، يحصل الكيان على نوع جديد: + +``` +TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section" +``` + +هذا يميز الأقسام عن الصفحات عند الاستعلام عن التتبع: + +| الكيان | النوع | متى يتم استخدامه | +|---|---|---| +| Document | `tg:Document` | الملف الذي تم رفعه أصلاً | +| Page | `tg:Page` | تنسيقات قائمة على الصفحات (PDF، PPTX، XLSX) | +| Section | `tg:Section` | تنسيقات غير قائمة على الصفحات (DOCX، HTML، MD، إلخ) | +| Image | `tg:Image` | صور مضمنة (مخزنة، وغير معالجة) | +| Chunk | `tg:Chunk` | إخراج وحدة تقسيم المستند | +| Subgraph | `tg:Subgraph` | إخراج KG | + +يتم تعيين النوع بواسطة جهاز فك الترميز بناءً على ما إذا كان يقوم بتجميع حسب الصفحة أم أنه يصدر قسمًا كاملاً للمستند. تكتسب `provenance/triples.py` معلمة اختيارية `section` — عندما تكون `true`، يتم تصنيف الكيان على أنه `tg:Section` بدلاً من `tg:Page`. + +#### سلسلة التتبع الكاملة + +``` +ثلاثية KG + → subgraph (تتبع الاستخراج) + → chunk (char_offset، char_length داخل الصفحة) + → page/section (page_number، char_offset، char_length داخل المستند، mime_type، element_types) + → document (الملف الأصلي في أمين المكتبة) +``` + +كل رابط هو مجموعة من الثلاثيات في الرسم البياني المسمى `GRAPH_SOURCE`. + +### التثبيت + +تأكد من أن لديك Python 3.6+ مثبتًا. + +```bash +pip install unstructured +``` + +### الاستخدام + +```python +from unstructured.partition.auto import partition + +# مثال على ملف PDF +pdf = partition(filename="path/to/your/document.pdf") + +# مثال على ملف HTML +html = partition(filename="path/to/your/document.html") +``` + +سيقوم هذا بتقسيم المستند إلى عناصر مثل العناوين والنصوص والجداول والصور. يمكنك بعد ذلك معالجة هذه العناصر بشكل منفصل. + +### الاعتبارات + +- **الأداء:** قد يكون تقسيم المستندات الكبيرة أمرًا مكلفًا من الناحية الحسابية. ضع في اعتبارك استخدام التخزين المؤقت أو المعالجة المتوازية للمستندات الكبيرة جدًا. +- **الدقة:** دقة التقسيم تعتمد على تنسيق المستند. قد تتطلب بعض المستندات معالجة خاصة للحصول على أفضل النتائج. + +### المساهمة + +إذا كنت ترغب في المساهمة في `unstructured`، فيرجى إرسال طلب سحب. نحن نقبل المساهمات من جميع أنواع. + +### الترخيص + +`unstructured` مرخصة بموجب رخصة Apache 2.0. \ No newline at end of file diff --git a/docs/tech-specs/universal-decoder.he.md b/docs/tech-specs/universal-decoder.he.md new file mode 100644 index 00000000..79209aef --- /dev/null +++ b/docs/tech-specs/universal-decoder.he.md @@ -0,0 +1,196 @@ +# מפענח מסמכים אוניברסלי + +## כותרת + +מפענח מסמכים אוניברסלי המופעל על ידי `unstructured` — קבלת פורמטים נפוצים של מסמכים באמצעות שירות יחיד, עם תיעוד מלא של מקור הנתונים ושילוב עם ספריית ניהול מסמכים, תוך רישום מיקומי המקור כמטא-דאטה של גרף ידע למעקב מקצה לקצה. + +## בעיה + +ל-TrustGraph כיום יש מפענח ספציפי ל-PDF. תמיכה בפורמטים נוספים (DOCX, XLSX, HTML, Markdown, טקסט רגיל, PPTX וכו') דורשת או כתיבת מפענח חדש לכל פורמט או אימוץ ספריית חילוץ אוניברסלית. לכל פורמט יש מבנה שונה — חלקם מבוססי דפים, חלקם לא — ושרשרת התיעוד חייבת לתעד היכן בכל המסמך המקורי הגיע כל חלק של הטקסט שחולץ. + +## גישה + +### ספרייה: `unstructured` + +יש להשתמש ב-`unstructured.partition.auto.partition()` שמזהה באופן אוטומטי את הפורמט מסוג MIME או סיומת הקובץ ומחלצת אלמנטים מובנים (כותרת, טקסט, טבלה, פריט רשימה וכו'). כל אלמנט מכיל מטא-דאטה, כולל: + +- `page_number` (לפורמטים מבוססי דפים כמו PDF, PPTX) +- `element_id` (ייחודי לכל אלמנט) +- `coordinates` (מלבן תחום עבור PDF) +- `text` (תוכן הטקסט שחולץ) +- `category` (סוג אלמנט: כותרת, טקסט, טבלה וכו') + +### סוגי אלמנטים + +`unstructured` מחלץ אלמנטים מסוגים שונים ממסמכים. לכל אלמנט יש קטגוריה ומטא-דאטה נלווים: + +**אלמנטים טקסטואליים:** +- `Title` — כותרות סעיפים +- `NarrativeText` — פסקאות גוף +- `ListItem` — פריטי רשימה/רשימות ממוספרות +- `Header`, `Footer` — כותרות/כותרות שוליים של עמודים +- `FigureCaption` — כיתובים עבור תמונות/גרפיקה +- `Formula` — ביטויים מתמטיים +- `Address`, `EmailAddress` — פרטי התקשרות +- `CodeSnippet` — בלוקי קוד (מ-Markdown) + +**טבלאות:** +- `Table` — נתונים טבלאיים מובנים. `unstructured` מספק גם `element.text` (טקסט רגיל) וגם `element.metadata.text_as_html` (תגית HTML מלאה של `` עם שורות, עמודות וכותרות). עבור פורמטים עם מבנה טבלה מוגדר (DOCX, XLSX, HTML), החילוץ אמין מאוד. עבור PDF, זיהוי טבלאות תלוי באסטרטגיית `hi_res` עם ניתוח פריסה. + +**תמונות:** +- `Image` — תמונות מוטמעות שזוהו באמצעות ניתוח פריסה (דורש אסטרטגיית `hi_res`). עם `extract_image_block_to_payload=True`, מחזיר את נתוני התמונה כ-base64 ב-`element.metadata.image_base64`. טקסט OCR מהתמונה זמין ב-`element.text`. + +### טיפול בטבלאות + +טבלאות הן פלט ברמה ראשונה. כאשר המפענח נתקל באלמנט `Table`, הוא שומר על מבנה ה-HTML במקום לפשט לטקסט רגיל. זה נותן למחלץ ה-LLM במעלה הזרם קלט טוב יותר לשליפה של ידע מובנה מנתונים טבלאיים. + +הטקסט של העמוד/הסעיף מורכב באופן הבא: +- אלמנטים טקסטואליים: טקסט רגיל, המחוברים עם שורות חדשות. +- אלמנטים של טבלאות: תגית טבלה HTML מ-`text_as_html`, עטופה בתגית `
` כך שה-LLM יכול להבחין בין טבלאות לבין טקסט רגיל. + +לדוגמה, עמוד עם כותרת, פסקה וטבלה מייצר: + +``` +סקירה פיננסית + +ההכנסות גדלו ב-15% שנה אחר שנה, הודות לאימוץ ארגוני. + +
+ +רבעון 1 +רבעון 2 +
רבעוןהכנסותצמיחה
$12 מיליון12%
$14 מיליון17%
+``` + +זה שומר על מבנה הטבלה במהלך חלוקה לחלקים ולתוך צינור החילוץ, שבו ה-LLM יכול לחלץ קשרים ישירות מתאים מובנים ולא לנחש על התאמת עמודות מרווח לבן. + +### טיפול בתמונות + +תמונות מחולצות ומאוחסנות בספריית הניהול כמסמכים משניים עם `document_type="image"` ו-ID `urn:image:{uuid}`. הם מקבלים משולשים של תיעוד מסוג `tg:Image`, המקושרים לעמוד/סעיף האב שלהם באמצעות `prov:wasDerivedFrom`. מטא-דאטה של תמונה (קואורדינטות, מימדים, `element_id`) נרשמים בתיעוד. + +**חשוב, תמונות אינן מופצות כפלט של `TextDocument`.** הן מאוחסנות בלבד — אינן נשלחות במעלה הזרם למחלק או לכל צינור עיבוד טקסט. זה מכוון: + +1. אין עדיין צינור לעיבוד תמונות (שילוב מודל ראייה הוא עבודה עתידית) +2. העברת נתוני תמונה ב-base64 או פיסות OCR לצינור חילוץ הטקסט תיצור משולשים של גרף ידע "זבל". + +תמונות גם אינן נכללות בטקסט העמוד המורכב — כל אלמנטי `Image` מושמטים בשקט כאשר מחברים טקסט של אלמנטים עבור עמוד/סעיף. שרשרת התיעוד רושמת שתמונות קיימות ואיפה שהן הופיעו במסמך, כך שניתן יהיה לשלוף אותן על ידי צינור עיבוד תמונות עתידי מבלי לטעון מחדש את המסמך. + +#### עבודה עתידית + +- הכוונת ישויות `tg:Image` למודל ראייה לתיאור, פרשנות דיאגרמות או חילוץ נתוני תרשימים. +- אחסון תיאורי תמונה כמסמכים טקסטואליים שמוזנים לצינור החלוקה/חילוץ הסטנדרטי. +- קישור ידע שנחצה חזרה לתמונות מקור באמצעות תיעוד. + +### אסטרטגיות סעיפים + +לפורמטים מבוססי דפים (PDF, PPTX, XLSX), אלמנטים תמיד מקובצים לפי עמוד/שקופית/גיליון תחילה. עבור פורמטים שאינם מבוססי דפים (DOCX, HTML, Markdown וכו'), למפענח יש אסטרטגיה לחלוקת המסמך לסעיפים. זה מוגדר בזמן ריצה באמצעות `--section-strategy`. + +כל אסטרטגיה היא פונקציית קיבוץ על רשימת האלמנטים של `unstructured`. הפלט הוא רשימת קבוצות אלמנטים; שאר הצינור (הרכבת טקסט, אחסון בספריית הניהול, תיעוד, פליטת `TextDocument`) זהים ללא קשר לאסטרטגיה. + +#### `whole-document` (ברירת מחדל) + +פליטת כל המסמך כסעיף יחיד. תן למחלק במעלה הזרם לטפל בכל החלוקה. + +- גישה פשוטה, נקודת התחלה טובה. +- עשויה ליצור `TextDocument` גדול מאוד עבור קבצים גדולים, אך המחלק מטפל בכך. +- הטוב ביותר כאשר אתה רוצה הקשר מרבי לכל סעיף. + +#### `heading` + +פיצול בכותרות (`Title`). כל סעיף הוא כותרת וכל התוכן עד לכותרת ברמה שווה או גבוהה יותר. כותרות מקוננות יוצרות סעיפים מקוננים. + +- מייצר יחידות מגובשות מבחינה נושאית. +- עובד היטב עבור מסמכים מובנים (דוחות, מדריכים, מפרטים). +- נותן למחלץ ה-LLM הקשר של כותרת יחד עם התוכן. +- חוזר ל-`whole-document` אם לא נמצאות כותרות. + +#### `element-type` + +פיצול כאשר סוג האלמנט משתנה באופן משמעותי — במיוחד, התחלה של סעיף חדש במעברים בין טקסט נרטיבי לטבלאות. אלמנטים עוקבים מאותה קטגוריה רחבה (טקסט, טקסט, טקסט או טבלה, טבלה) נשארים מקובצים. + +- שומר על טבלאות כסעיפים עצמאיים. +- טוב למסמכים עם תוכן מעורב (דוחות עם טבלאות נתונים). +- לטבלאות יש תשומת לב חילוץ ייעודית. + +#### `count` + +קיבוץ מספר קבוע של אלמנטים לכל סעיף. ניתן להגדרה באמצעות `--section-element-count` (ברירת מחדל: 20). + +- פשוט וצפוי. +- לא מכבד את מבנה המסמך. +- שימושי כברירת מחדל או לניסויים. + +#### `size` + +צבירת אלמנטים עד שמגיעים לגבול תווים, ואז התחלת סעיף חדש. מכבד את גבולות האלמנטים — לעולם לא מפצל באמצע אלמנט. ניתן להגדרה באמצעות `--section-max-size` (ברירת מחדל: 4000 תווים). + +- מייצר גדלים בערך אחידים של סעיפים. +- מכבד את גבולות האלמנטים (בניגוד למחלק במעלה הזרם). +- פשרה טובה בין שליטה במבנה ובגודל. +- אם אלמנט יחיד חורג מהגבול, הוא הופך לסעיף משלו. + +#### אינטראקציה עם פורמטים מבוססי דפים + +עבור פורמטים מבוססי דפים, הקיבוץ לפי עמוד תמיד מקבל עדיפות. אסטרטגיות סעיפים יכולות באופן אופציונלי להחיל *בתוך* עמוד אם הוא גדול מאוד (לדוגמה, עמוד PDF עם טבלה עצומה), דבר ששולט על ידי `--section-within-pages` (ברירת מחדל: false). כאשר זה כוזב, כל עמוד תמיד סעיף אחד ללא קשר לגודל. + +### זיהוי פורמט + +למפענח יש צורך לדעת את סוג MIME של המסמך כדי להעביר ל-`partition()` של `unstructured`. שתי אפשרויות: + +- **נתיב ספריית הניהול** (`document_id` מוגדר): אחסון מטא-דאטה של מסמך מהספרייה תחילה — זה נותן לנו את `kind` (סוג MIME) שנרשם בזמן ההעלאה. ואז אחסון תוכן מסמך. שתי קריאות לספריית הניהול, אך אחזור המטא-דאטה קל משקל. +- **נתיב מקומי** (תאימות לאחור, `data` מוגדר): אין מטא-דאטה זמין על ההודעה. השתמש ב-`python-magic` כדי לזהות את הפורמט מתוך בתים של תוכן כגיבוי. + +אין צורך בשינויים בסכימת `Document` — ספריית הניהול כבר מאחסנת את סוג ה-MIME. + +### ארכיטקטורה + +שירות `universal-decoder` יחיד שמבצע את הפעולות הבאות: + +1. מקבל הודעת `Document` (מקומית או באמצעות הפניה לספריית הניהול). +2. אם נתיב ספריית הניהול: אחסון מטא-דאטה של מסמך (קבלת סוג MIME), ואז אחסון תוכן. אם נתיב מקומי: זיהוי פורמט מתוך בתים של תוכן. +3. קריאה ל-`partition()` כדי לחלץ אלמנטים. +4. קיבוץ אלמנטים: לפי עמוד עבור פורמטים מבוססי דפים, לפי אסטרטגיית סעיף מוגדרת עבור פורמטים שאינם מבוססי דפים. +5. עבור כל עמוד/סעיף: + - יצירת ID `urn:page:{uuid}` או `urn:section:{uuid}`. + - הרכבת טקסט עמוד: טקסט רגיל, טבלאות כ-HTML, תמונות מושמטות. + - חישוב ההיסט מוחלט של כל אלמנט בתוך טקסט העמוד. + - שמירה בספריית הניהול כתיעוד משני. + - יצירת משולשים של תיעוד עם מטא-דאטה מיקומי. + - שליחת `TextDocument` במעלה הזרם לחלוקה. +6. עבור כל אלמנט תמונה: + - יצירת ID `urn:image:{uuid}`. + - שמירת נתוני תמונה בספריית הניהול כתיעוד משני. + - יצירת משולשים של תיעוד (מאוחסנים בלבד, אינם נשלחים במעלה הזרם). + +### טיפול בפורמטים + +| פורמט | סוג MIME | מבוסס עמוד | הערות | +|---|---|---|---| +| PDF | application/pdf | כן | קיבוץ לפי עמוד | +| DOCX | application/vnd.openxmlformats... | לא | משתמש באסטרטגיית סעיף | +| PPTX | application/vnd.openxmlformats... | כן | קיבוץ לפי שקופית | +| XLSX/XLS | application/vnd.openxmlformats... | כן | קיבוץ לפי גיליון | +| HTML | text/html | לא | משתמש באסטרטגיית סעיף | +| Markdown | text/markdown | לא | משתמש באסטרטגיית סעיף | +| רגיל | text/plain | לא | משתמש באסטרטגיית סעיף | +| CSV | text/csv | לא | משתמש באסטרטגיית סעיף | +| RST | text/x-rst | לא | משתמש באסטרטגיית סעיף | +| RTF | application/rtf | לא | משתמש באסטרטגיית סעיף | +| ODT | application/vnd.oasis... | לא | משתמש באסטרטגיית סעיף | +| TSV | text/tab-separated-values | לא | משתמש באסטרטגיית סעיף | + +### מטא-דאטה של תיעוד + +כל ישות עמוד/סעיף רושמת מטא-דאטה מיקומי כמשולשים של תיעוד בגרף `GRAPH_SOURCE`, ומאפשרת מעקב מלא מהמשולשים של גרף ידע חזרה למיקומי המסמך המקוריים. + +#### שדות קיימים (כבר ב-`derived_entity_triples`) + +- `page_number` — מספר עמוד/גיליון/שקופית (מוגדר מ-1, רק עבור פורמטים מבוססי עמודים) +- `char_offset` — היסט מוחלט של תווים של עמוד/סעיף זה בתוך הטקסט המלא של המסמך. +- `char_length` — אורך התווים של הטקסט של עמוד/סעיף זה. + +#### שדות חדשים (הרחבת `derived_entity_triples`) + +- `mime_type` — פורמט מסמך מקורי (לדוגמה, `application/pdf`) +- `element_types` — רשימה מופרדת בפסיקים של קטגוריות `unstructured` של אלמנטים (לדוגמה, `title, paragraph, table`). +- `provenance` — מידע על מקור הנתונים. \ No newline at end of file diff --git a/docs/tech-specs/universal-decoder.sw.md b/docs/tech-specs/universal-decoder.sw.md new file mode 100644 index 00000000..4e3a97ce --- /dev/null +++ b/docs/tech-specs/universal-decoder.sw.md @@ -0,0 +1,220 @@ +# Derekezi Universal ya Hati + +## Mada + +Derekezi universal ya hati inayotumiwa na `unstructured` — ingiza aina yoyote ya hati inayotumika kupitia huduma moja, pamoja na taarifa kamili kuhusu chanzo na ushirikiano na mtaalamu wa maktaba, huku ikiandika nafasi za asili kama metadata ya grafu ya maarifa kwa ufuatiliaji kamili. + +## Tatizo + +Sasa, derekezi ya TrustGraph inalenga tu hati za PDF. Kuunga mkono aina zingine (DOCX, XLSX, HTML, Markdown, maandishi safi, PPTX, n.k.) inahitaji ama kuandika derekezi mpya kwa kila aina au kutumia maktaba ya uondoaji wa universal. Kila aina ina muundo tofauti — baadhi zinategemea kurasa, huku zingine hazitegemei — na mnyororo wa chanzo lazima urekodize ambako kila sehemu ya maandishi iliyopatikana ilitoka kwenye hati asili. + +## Mbinu + +### Maktaba: `unstructured` + +Tumia `unstructured.partition.auto.partition()` ambayo hugundua kiotomatiki aina kutoka kwa mime type au upanuzi wa faili na huondoa vipengele vilivyopangwa (Kichwa, Nakala, Jedwali, Kipengele cha Orodha, n.k.). Kila kipengele kina metadata, pamoja na: + +- `page_number` (kwa aina zinazotumia kurasa kama vile PDF, PPTX) +- `element_id` (ya kipekee kwa kila kipengele) +- `coordinates` (sanduku la mipaka kwa PDFs) +- `text` (maandishi yaliyopatikana) +- `category` (aina ya kipengele: Kichwa, Nakala, Jedwali, n.k.) + +### Aina za Vipengele + +`unstructured` huondoa vipengele vilivyopangwa kutoka kwenye hati. Kila kipengele kina aina na metadata inayohusiana: + +**Vipengele vya maandishi:** +- `Title` — vichwa vya sehemu +- `NarrativeText` — aya za mwili +- `ListItem` — vipengele vya orodha (pointi/nambari) +- `Header`, `Footer` — vichwa/miguu ya ukurasa +- `FigureCaption` — maandishi ya maelezo kwa picha/akili +- `Formula` — maandishi ya hesabu +- `Address`, `EmailAddress` — maelezo ya mawasiliano +- `CodeSnippet` — vipengele vya nambari (kutoka kwenye maandishi) + +**Jedwali:** +- `Table` — data iliyopangwa katika meza. `unstructured` hutoa `element.text` (maandishi safi) na `element.metadata.text_as_html` (HTML kamili ya `` pamoja na mistari, safu, na vichwa). Kwa aina zilizo na muundo wazi wa jedwali (DOCX, XLSX, HTML), uondoaji una uaminifu mkubwa. Kwa PDFs, ugunduzi wa jedwali hutegemea mkakati wa `hi_res` pamoja na uchambuzi wa muundo. + +**Picha:** +- `Image` — picha zilizowekwa ndani ambazo hugunduliwa kupitia uchambuzi wa muundo (inahitaji mkakati wa `hi_res`). Pamoja na `extract_image_block_to_payload=True`, inarudisha data ya picha kama base64 katika `element.metadata.image_base64`. Maandishi ya maandishi kutoka kwenye picha yanapatikana katika `element.text`. + +### Usimamizi wa Jedwali + +Jedwali hupewa umuhimu wa pekee. Pale derekezi inapokutana na kipengele cha `Table`, inahifadhi muundo wa HTML badala ya kuirekebisha kuwa maandishi safi. Hii inatoa derekezi ya LLM (Large Language Model) ya chini ya uondoaji ya taarifa bora kwa kuchimbua maarifa kutoka kwa data iliyopangwa. + +Maandishi ya ukurasa/sehemu yanakusanywa kama ifuatavyo: +- Vipengele vya maandishi: maandishi safi, yakiunganishwa na mistari mipya +- Vipengele vya jedwali: alama ya HTML ya `
` kutoka `text_as_html`, ambayo inazingatiwa ili derekezi ya LLM iweze kutofautisha jedwali na maandishi. + +Kwa mfano, ukurasa wenye kichwa, aya, na jedwali hutengenezwa kama ifuatavyo: + +``` +Muhtasari wa Kifedha + +Mapato yaliongezeka kwa 15% mwaka jana kutokana na matumizi ya kampuni. + +
+ + + +
Kila MaraMapatoKukua
Q1$12M12%
Q2$14M17%
+``` + +Hii inahifadhi muundo wa jedwali wakati wa kuunganisha na katika mlolongo wa uondoaji, ambapo derekezi ya LLM inaweza kuchimbua uhusiano moja kwa moja kutoka kwa seli zilizopangwa badala ya kujaribu nadharia kuhusu ulinganishi wa safu kutoka kwa umbali. + +### Usimamizi wa Picha + +Picha zinaondolewa na kuhifadhiwa katika mtaalamu wa maktaba kama hati ndogo zenye `document_type="image"` na `urn:image:{uuid}` ID. Inapata triples za chanzo pamoja na aina `tg:Image`, ambazo zinahusiana na ukurasa/sehemu yake ya asili kupitia `prov:wasDerivedFrom`. Metadata ya picha (nafasi, vipimo, `element_id`) inarekodiwa katika chanzo. + +**Muhimu, picha HAZIPI tokelezwa kama matokeo ya `TextDocument`.** Inahifadhiwa tu — haitumwi kwa derekezi ya sehemu au mlolongo wowote wa kuchakata maandishi. Hii ni kwa makusudi: + +1. Bado hakuna mlolongo wa kuchakata picha (kuunganisha na modeli ya maono ni kazi ya baadaye) +2. Kupeleka data ya picha au vipande vya maandishi kutoka kwa OCR kwenye mlolongo wa uondoaji wa maandishi kutatoa triples za KG (Knowledge Graph) zisizo na maana. + +Picha pia hazijumuishwi katika maandishi ya ukurasa — vipengele vyovyote vya `Image` hupita bila kutambuliwa wakati wa kuunganisha maandishi ya kipengele kwa ukurasa/sehemu. Mnyororo wa chanzo unaandika kwamba picha zipo na zilipoonekana katika hati, hivyo zinaweza kuchukuliwa na mlolongo wa baadaye wa kuchakata picha bila kuhitajika kurejesha hati. + +#### Kazi za Baadaye + +- Tuma vitu vya `tg:Image` kwa modeli ya maono kwa ajili ya maelezo, tafsiri ya michoro, au uondoaji wa data ya chati. +- Hifadhi maelezo ya picha kama hati ndogo za maandishi ambazo hufika katika mlolongo wa kawaida wa kuunganisha/uondoaji. +- Unganisha maarifa yaliyopatikana nyuma kwenye picha za asili kupitia chanzo. + +### Mikakati ya Sehemu + +Kwa aina zinazotumia kurasa (PDF, PPTX, XLSX), vipengele daima huunganishwa kwa ukurasa/slide/karatasi kwanza. Kwa aina ambazo hazitumii kurasa (DOCX, HTML, Markdown, n.k.), derekezi inahitaji mkakati wa kuainisha hati katika sehemu. Hii inaweza kubadilishwa wakati wa utendaji kupitia `--section-strategy`. + +Kila mkakati ni kazi ya kuunganisha juu ya orodha ya vipengele vya `unstructured`. Matokeo ni orodha ya vikundi vya vipengele; mlolongo mwingine (kuunganisha maandishi, kuhifadhi katika mtaalamu wa maktaba, chanzo, matokeo ya `TextDocument`) ni sawa bila kujali mkakati. + +#### `whole-document` (chaguo-msingi) + +Tuma hati nzima kama sehemu moja. Acha derekezi ya chini ya uunganisha iweze kuainisha yote. + +- Mbinu rahisi, kiwango kizuri +- Inaweza kuzalisha `TextDocument` kubwa kwa faili kubwa, lakini derekezi ya chini ya uunganisha inaweza kushughulikia hili +- Ni bora wakati unataka muktadha mwingi kwa kila sehemu + +#### `heading` + +Aina katika vipengele vya vichwa (`Title`). Kila sehemu ni kichwa na yote yaliyo yafuatayo hadi kichwa cha kiwango sawa au cha juu. Vichwa vilivyoingiliana huunda sehemu zilizounganishwa. + +- Inazalisha vitengo vya mada ambavyo vina maana +- Inafaa kwa hati zilizopangwa (ripoti, manwal, vipimo) +- Inatoa kwa derekezi ya LLM muktadha wa vichwa pamoja na maudhui +- Inarudi kwenye `whole-document` ikiwa hakuna vichwa vilivyopatikana + +#### `element-type` + +Aina wakati aina ya kipengele inabadilika sana — haswa, anza sehemu mpya katika mabadiliko kati ya maandishi na jedwali. Vipengele vilivyofuata vya aina moja (maandishi, maandishi, maandishi au jedwali, jedwali) huendelea kuunganishwa. + +- Inahifadhi jedwali kama sehemu zilizojitenga +- Ni nzuri kwa hati zilizo na maudhui mchanganyiko (ripoti na meza za data) +- Jedwali hupata umakini maalum wa uondoaji + +#### `count` + +Unganisha idadi fulani ya vipengele kwa kila sehemu. Inaweza kubadilishwa kupitia `--section-element-count` (chaguo-msingi: 20). + +- Rahisi na yanayotabirika +- Hayazingati muundo wa hati +- Ni muhimu kama njia mbadala au kwa majaribio + +#### `size` + +Unganisha vipengele hadi kikomo cha herufi kifikie, kisha anza sehemu mpya. Inazingatia mipaka ya kipengele — haigawisi katikati ya kipengele. Inaweza kubadilishwa kupitia `--section-max-size` (chaguo-msingi: 4000 herufi). + +- Inazalisha ukubwa wa sehemu unaozingatia +- Inazingatia mipaka ya kipengele (tofauti na derekezi ya chini ya uunganisha) +- Ni suluhisho bora kati ya muundo na udhibiti wa ukubwa +- Ikiwa kipengele kimoja kinazidi kikomo, kinakuwa sehemu yake mwenyewe + +#### Mwingiliano na Aina Zinazotumia Kurasa + +Kwa aina zinazotumia kurasa, uunganishaji wa ukurasa daima huwapa kipaumbele. Mikakati ya sehemu inaweza kutumika *ndani* ya ukurasa ikiwa ukurasa ni kubwa sana (kwa mfano, ukurasa wa PDF wenye jedwali kubwa sana), hii inadhibitiwa na `--section-within-pages` (chaguo-msingi: false). Wakati chaguo hili limezimwa, kila ukurasa ni sehemu moja bila kujali ukubwa wake. + +### Ugunduzi wa Aina + +Derekezi inahitaji kujua aina ya hati ili iweze kuipitisha kwa `partition()` ya `unstructured`. Kuna njia mbili: + +- **Njia ya mtaalamu wa maktaba** (`document_id` imewekwa): kwanza pata metadata ya hati kutoka kwa mtaalamu wa maktaba — hii inatuonyesha `kind` (aina) ambayo ilirekodiwa wakati wa kupakia. Kisha pata maudhui ya hati. Hii inahitaji simu mbili za mtaalamu wa maktaba, lakini kupata metadata ni rahisi. +- **Njia ya ndani** (utangamano wa nyuma, `data` imewekwa): hakuna metadata inayopatikana kwenye ujumbe. Tumia `python-magic` kuchunguza aina kutoka kwa bytes za maudhui kama njia mbadala. + +Hakuna mabadiliko yanayohitajika kwenye schema ya `Document` — mtaalamu wa maktaba hurejesha aina ya mime. + +### Muundo + +Huduma moja ya `universal-decoder` ambayo: + +1. Inapokea ujumbe wa `Document` (ndani au kupitia marejeleo ya mtaalamu wa maktaba) +2. Ikiwa ni njia ya mtaalamu wa maktaba: pata metadata ya hati (pata aina), kisha pata maudhui. Ikiwa ni njia ya ndani: chunguza aina kutoka kwa bytes za maudhui. +3. Inaitisha `partition()` ili kuondoa vipengele +4. Inaainisha vipengele: kwa ukurasa kwa aina zinazotumia kurasa, kwa mkakati wa sehemu uliopangwa kwa aina ambazo hazitumii kurasa +5. Kwa kila ukurasa/sehemu: + - Inazalisha `urn:page:{uuid}` au `urn:section:{uuid}` ID + - Inaunganisha maandishi ya ukurasa: maandishi safi, jedwali kama HTML, picha zinarudiwa + - Inahesabu nafasi za herufi kwa kila kipengele ndani ya maandishi ya ukurasa + - Inahifadhi katika mtaalamu wa maktaba kama hati ndogo + - Inazalisha triples za chanzo na metadata ya nafasi + - Inatuma `TextDocument` chini ya uunganishaji +6. Kwa kila kipengele cha picha: + - Inazalisha `urn:image:{uuid}` ID + - Inahifadhi data ya picha katika mtaalamu wa maktaba kama hati ndogo + - Inazalisha triples za chanzo (zinawekwa tu, hazitumwi chini) + +### Usanidi wa Huduma + +Majadiliano ya mstari wa amri: + +``` +--strategy Mbinu ya kuainisha: auto, hi_res, fast (chaguo-msingi: auto) +--languages Orodha ya msimbo wa lugha inayotumika kwa OCR (chaguo-msingi: eng) +--section-strategy Mbinu ya kuunganisha sehemu: whole-document, heading, element-type, + count, size (chaguo-msingi: whole-document) +--section-element-count Vipengele kwa kila sehemu kwa mbinu ya 'count' (chaguo-msingi: 20) +--section-max-size Kikomo cha herufi kwa kila sehemu kwa mbinu ya 'size' (chaguo-msingi: 4000) +--section-within-pages Tumia mkakati wa sehemu ndani ya ukurasa pia (chaguo-msingi: false) +``` + +Pia, majadiliano ya kawaida ya `FlowProcessor` na folyo ya mtaalamu wa maktaba. + +### Ushirikiano wa Flow + +Derekezi ya universal huishia katika nafasi sawa ya mlolongo wa uendeshaji kama derekezi ya PDF iliyopo: + +``` +Hati → [derekezi-universal] → TextDocument → [derekezi-ya-kuunganisha] → Sehemu → ... +``` + +Inajisajili: +- Mtumiaji wa `input` (schema ya Hati) +- Mtayarishaji wa `output` (schema ya TextDocument) +- Mtayarishaji wa `triples` (schema ya Triples) +- Ombi/jibu la mtaalamu wa maktaba (kwa kupata na kuhifadhi hati ndogo) + +### Uwekaji + +- Chini mpya: `trustgraph-flow-universal-decoder` +- Utendakazi: `unstructured[all-docs]` (inajumuisha PDF, DOCX, PPTX, n.k.) +- Inaweza kuendeshwa pamoja au kubadilisha derekezi ya PDF iliyopo kulingana na usanidi wa mlolongo +- Derekezi ya PDF iliyopo inabaki inapatikana kwa mazingira ambapo utendakazi wa `unstructured` ni mzito sana. + +### Mabadiliko + +| Komponenti | Mabadiliko | +|------------------------------|-------------------------------------------------| +| `provenance/namespaces.py` | Ongeza `TG_SECTION_TYPE`, `TG_IMAGE_TYPE`, `TG_ELEMENT_TYPES`, `TG_TABLE_COUNT`, `TG_IMAGE_COUNT` | +| `provenance/triples.py` | Ongeza `mime_type`, `element_types`, `table_count`, `image_count` kwa `kwargs` | +| `provenance/__init__.py` | Exporti mara kwa mara | +| Mpya: `decoding/universal/` | Moduli mpya ya derekezi | +| `setup.cfg` / `pyproject` | Ongeza utendakazi wa `unstructured[all-docs]` | +| Docker | Pata picha mpya ya chumba | +| Maelezo ya mlolongo | Unganisha derekezi-universal kama input ya hati | + +### Mambo ambayo Hayabadiliki + +- Derekezi ya kuchakata (Inapokea `TextDocument`, inafanya kama ilivyokuwa) +- Vitu vya uondoaji (Inapokea `Sehemu`, inafanya kama ilivyokuwa) +- Schema ya `Document` — inahitaji maelezo yafuatayo: + - `file_name`: Jina la faili. + - `file_type`: Aina ya faili. \ No newline at end of file diff --git a/docs/tech-specs/universal-decoder.zh-cn.md b/docs/tech-specs/universal-decoder.zh-cn.md new file mode 100644 index 00000000..fa61ea31 --- /dev/null +++ b/docs/tech-specs/universal-decoder.zh-cn.md @@ -0,0 +1,289 @@ +# 通用文档解码器 + +## 概述 + +一个由 `unstructured` 驱动的通用文档解码器,它支持通过单个服务处理各种常见的文档格式。该服务具有完整的溯源功能和库管理员集成,记录源位置作为知识图谱元数据,从而实现端到端的可追溯性。 + +## 问题 + +目前,TrustGraph 仅有一个用于 PDF 文件的解码器。支持其他格式(DOCX、XLSX、HTML、Markdown、纯文本、PPTX 等)需要要么为每种格式编写新的解码器,要么采用一个通用的提取库。每种格式的结构都不同——有些是基于页面的,有些不是——并且溯源链必须记录每个提取的文本片段在原始文档中的位置。 + +## 解决方案 + +### 库:`unstructured` + +使用 `unstructured.partition.auto.partition()` 函数,该函数可以自动检测格式(根据 MIME 类型或文件扩展名),并提取结构化元素(标题、正文、表格、列表项等)。每个元素都包含元数据,包括: + +- `page_number`(对于基于页面的格式,如 PDF、PPTX) +- `element_id`(每个元素唯一) +- `coordinates`(PDF 文件的边界框) +- `text`(提取的文本内容) +- `category`(元素类型:标题、正文、表格等) + +### 元素类型 + +`unstructured` 提取文档中的各种类型的元素,每个元素都有一个类别和相关的元数据: + +**文本元素:** +- `Title` — 段落标题 +- `NarrativeText` — 正文段落 +- `ListItem` — 项目符号/编号列表项 +- `Header`, `Footer` — 页面页眉/页脚 +- `FigureCaption` — 图形/图像的标题 +- `Formula` — 数学表达式 +- `Address`, `EmailAddress` — 联系信息 +- `CodeSnippet` — 代码块(来自 Markdown) + +**表格:** +- `Table` — 结构化的表格数据。`unstructured` 提供了 `element.text`(纯文本)和 `element.metadata.text_as_html`(完整的 HTML `` 标签,保留了行、列和标题)。对于具有显式表格结构的格式(DOCX、XLSX、HTML),提取的可靠性很高。对于 PDF 文件,表格检测依赖于 `hi_res` 策略和布局分析。 + +**图像:** +- `Image` — 检测到的嵌入图像(需要 `hi_res` 策略)。如果设置 `extract_image_block_to_payload=True`,则将图像数据作为 base64 编码的字符串返回到 `element.metadata.image_base64` 中。图像中的 OCR 文本位于 `element.text` 中。 + +### 表格处理 + +表格是主要的输出。当解码器遇到 `Table` 元素时,它会保留 HTML 结构,而不是将其扁平化为纯文本。这为下游的 LLM 提取器提供了更好的输入,以便从表格数据中提取结构化知识。 + +页面/部分文本的组装方式如下: +- 文本元素:纯文本,用换行符连接 +- 表格元素:来自 `text_as_html` 的 HTML 表格标记,并用 `
` 标记包装,以便 LLM 区分表格和正文。 + +例如,一个页面包含标题、段落和表格,其内容如下: + +``` +Financial Overview + +Revenue grew 15% year-over-year driven by enterprise adoption. + +
+ + + +
QuarterRevenueGrowth
Q1$12M12%
Q2$14M17%
+``` + +这在分块和提取流水线中保留了表格结构,LLM 可以直接从结构化单元格中提取关系,而无需猜测列的对齐方式。 + +### 图像处理 + +图像会被提取并存储在库管理员中,作为具有 `document_type="image"` 和 `urn:image:{uuid}` ID 的子文档。它们会生成带有类型 `tg:Image` 的溯源三元组,并通过 `prov:wasDerivedFrom` 链接到其父页面/部分。图像元数据(坐标、尺寸、`element_id`)会记录在溯源信息中。 + +**重要的是,图像不会作为 `TextDocument` 输出。** 它们仅被存储,不会被发送到分块器或任何文本处理流水线。这是故意的: + +1. 尚未建立图像处理流水线(视觉模型集成是未来的工作)。 +2. 将 base64 编码的图像数据或 OCR 片段馈送到文本提取流水线会产生无效的知识图谱三元组。 + +图像也被排除在组装的页面文本之外。当连接一个页面/部分的元素文本时,任何 `Image` 元素都会被静默地跳过。溯源链会记录图像的存在以及它们在文档中出现的位置,以便在将来的图像处理流水线中可以拾取它们,而无需重新导入文档。 + +#### 未来工作 + +- 将 `tg:Image` 实体路由到视觉模型,用于描述、图表解释或图表数据提取。 +- 将图像描述存储为文本子文档,这些子文档会馈送到标准的 chunking/提取流水线。 +- 通过溯源将提取的知识链接回源图像。 + +### 部分策略 + +对于基于页面的格式(PDF、PPTX、XLSX),元素始终首先按页面分组。对于非基于页面的格式(DOCX、HTML、Markdown 等),解码器需要一种策略来将文档拆分为多个部分。这可以通过运行时配置的 `--section-strategy` 参数进行配置。 + +每种策略都是一个分组函数,作用于 `unstructured` 元素的列表。输出是一个元素组的列表;其余流水线(文本组装、库管理员存储、溯源、`TextDocument` 输出)与策略无关。 + +#### `whole-document` (默认) + +将整个文档作为一个单独的部分输出。由下游的分块器处理所有拆分。 + +- 最简单的方案,作为基线。 +- 对于大型文件,可能会生成非常大的 `TextDocument`,但分块器会处理这种情况。 +- 当希望每个部分包含最大的上下文时,使用此选项。 + +#### `heading` + +在标题元素(`Title`)处进行拆分。每个部分是一个标题以及直到下一个相同或更高级别的标题的所有内容。嵌套的标题会创建嵌套的部分。 + +- 生成具有主题相关性的单元。 +- 适用于结构化文档(报告、手册、规范)。 +- 向提取 LLM 提供标题上下文以及内容。 +- 如果未找到标题,则回退到 `whole-document`。 + +#### `element-type` + +当元素类型发生显着变化时进行拆分,特别是,从正文文本和表格之间的转换开始一个新的部分。连续的相同宽泛类别的元素(文本、文本、文本或表格、表格、表格)保持分组。 + +- 保持表格作为独立的部分。 +- 适用于具有混合内容的文档(包含数据表格的报告)。 +- 表格会获得专门的提取关注。 + +#### `count` + +每部分包含固定数量的元素。可以通过 `--section-element-count` 参数进行配置(默认:20)。 + +- 简单且可预测。 +- 不尊重文档结构。 +- 用作回退选项或用于实验。 + +#### `size` + +持续累积元素,直到达到字符限制,然后开始一个新的部分。尊重元素边界,绝不会在元素内部进行拆分。可以通过 `--section-max-size` 参数进行配置(默认:4000 个字符)。 + +- 生成大致均匀大小的部分。 +- 尊重元素边界(与下游分块器不同)。 +- 在结构和大小控制之间取得良好的平衡。 +- 如果单个元素超过限制,则它会成为其自己的部分。 + +#### 基于页面的格式交互 + +对于基于页面的格式,页面分组始终具有优先性。部分策略可以选择性地在非常大的页面内部应用(例如,一个包含非常大的表格的 PDF 页面),由 `--section-within-pages` 参数控制(默认:false)。当设置为 false 时,每个页面始终是一个部分,无论其大小如何。 + +### 格式检测 + +解码器需要知道文档的 MIME 类型,以便将其传递给 `unstructured` 的 `partition()` 函数。有两种方法: + +- **库管理员路径**(设置了 `document_id`):首先从库管理员中获取文档元数据,这会提供 `kind`(MIME 类型),然后获取文档内容。这需要两次库管理员调用,但元数据获取是轻量级的。 +- **内联路径**(后备方案,设置了 `data`):没有关于消息的元数据。使用 `python-magic` 从内容字节中检测格式,作为后备方案。 + +不需要对 `Document` 模式进行任何更改,因为库管理员已经存储了 MIME 类型。 + +### 架构 + +一个名为 `universal-decoder` 的单个服务,该服务: + +1. 接收一个 `Document` 消息(内联或通过库管理员引用)。 +2. 如果使用库管理员路径:获取文档元数据(获取 MIME 类型),然后获取内容。如果使用内联路径:使用 `python-magic` 从内容字节检测格式。 +3. 调用 `partition()` 函数以提取元素。 +4. 按以下方式对元素进行分组:对于基于页面的格式,按页面分组;对于非基于页面的格式,按配置的策略分组。 +5. 对于每个页面/部分: + - 生成一个 `urn:page:{uuid}` 或 `urn:section:{uuid}` ID。 + - 组装页面文本:正文作为纯文本,表格作为 HTML,图像被跳过。 + - 计算每个元素在页面文本中的字符偏移量。 + - 保存到库管理员中作为子文档。 + - 计算带有位置元数据的溯源三元组。 + - 将 `TextDocument` 发送到下游进行分块。 +6. 对于每个图像元素: + - 生成一个 `urn:image:{uuid}` ID。 + - 将图像数据保存到库管理员中作为子文档。 + - 计算溯源三元组(仅存储,不发送到下游)。 + +### 格式处理 + +| 格式 | MIME 类型 | 基于页面 | 备注 | +|-----------|--------------------------------------------|----------|--------------------------------------------| +| PDF | `application/pdf` | 是 | 按页面分组 | +| DOCX | `application/vnd.openxmlformats...` | 否 | 使用部分策略 | +| PPTX | `application/vnd.openxmlformats...` | 是 | 按幻灯片分组 | +| XLSX/XLS | `application/vnd.openxmlformats...` | 是 | 按工作表分组 | +| HTML | `text/html` | 否 | 使用部分策略 | +| Markdown | `text/markdown` | 否 | 使用部分策略 | +| 纯文本 | `text/plain` | 否 | 使用部分策略 | +| CSV | `text/csv` | 否 | 使用部分策略 | +| RST | `text/x-rst` | 否 | 使用部分策略 | +| RTF | `application/rtf` | 否 | 使用部分策略 | +| ODT | `application/vnd.oasis...` | 否 | 使用部分策略 | +| TSV | `text/tab-separated-values` | 否 | 使用部分策略 | + +### 溯源元数据 + +每个页面/部分实体会记录位置元数据,作为 `GRAPH_SOURCE` 命名图中位置元数据的溯源三元组。 + +#### 现有字段(已包含在 `derived_entity_triples` 中) + +- `page_number` — 页面/工作表/幻灯片编号(从 1 开始,仅适用于基于页面的格式) +- `char_offset` — 此页面/部分在整个文档文本中的字符偏移量 +- `char_length` — 此页面/部分的文本的字符长度 + +#### 新字段(扩展 `derived_entity_triples`) + +- `mime_type` — 原始文档格式(例如,`application/pdf`) +- `element_types` — 使用 `unstructured` 提取的元素的类别的逗号分隔列表(例如,`Title,NarrativeText,Table`) +- `table_count` — 此页面/部分中的表格数量 +- `image_count` — 此页面/部分中的图像数量 + +这些需要新的 TG 命名空间谓词: + +``` +TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section" +TG_IMAGE_TYPE = "https://trustgraph.ai/ns/Image" +TG_ELEMENT_TYPES = "https://trustgraph.ai/ns/elementTypes" +TG_TABLE_COUNT = "https://trustgraph.ai/ns/tableCount" +TG_IMAGE_COUNT = "https://trustgraph.ai/ns/imageCount" +``` + +图像 URN 方案:`urn:image:{uuid}` + +(`TG_MIME_TYPE` 已经存在。) + +#### 完整的溯源链 + +``` +知识图谱三元组 + → subgraph (提取溯源) + → chunk (页面/部分的字符偏移量和长度) + → page/section (页面编号、字符偏移量和长度、MIME 类型、元素类型) + → document (库管理员中的原始文件) +``` + +每个链接都是 `GRAPH_SOURCE` 命名图中一组三元组。 + +### 服务配置 + +命令行参数: + +``` +--strategy 分区策略:auto, hi_res, fast (默认:auto) +--languages 逗号分隔的 OCR 语言代码 (默认: eng) +--section-strategy 部分分组:whole-document, heading, element-type, + count, size (默认: whole-document) +--section-element-count 每个部分包含的元素数量(`count` 策略),(默认: 20) +--section-max-size 每个部分的最大字符数(`size` 策略),(默认: 4000 个字符) +--section-within-pages 是否在页面内部应用部分策略 (默认: false) +``` + +以及标准的 `FlowProcessor` 和库管理员队列参数。 + +### 流集成 + +通用解码器在处理流程中占据与现有 PDF 解码器相同的 position: + +``` +Document → [通用解码器] → TextDocument → [分块器] → Chunk → ... +``` + +它注册: +- `input` 消费者(`Document` 模式) +- `output` 生产者(`TextDocument` 模式) +- `triples` 生产者(`Triples` 模式) +- 库管理员请求/响应(用于获取和创建子文档) + +### 部署 + +- 新的容器:`trustgraph-flow-universal-decoder` +- 依赖项:`unstructured[all-docs]`(包含 PDF、DOCX、PPTX 等) +- 可以与现有的 PDF 解码器并行运行或替换它,具体取决于流程配置。 +- 现有的 PDF 解码器仍然可用,适用于 `unstructured` 依赖项过多的环境。 + +### 变更内容 + +| 组件 | 变更 | +|------------------------------|-------------------------------------------------| +| `provenance/namespaces.py` | 添加 `TG_SECTION_TYPE`、`TG_IMAGE_TYPE`、`TG_ELEMENT_TYPES`、`TG_TABLE_COUNT`、`TG_IMAGE_COUNT` | +| `provenance/triples.py` | 添加 `mime_type`、`element_types`、`table_count`、`image_count` 参数 | +| `provenance/__init__.py` | 导出新的常量 | +| 新的:`decoding/universal/` | 新的解码器服务模块 | +| `setup.cfg` / `pyproject` | 添加 `unstructured[all-docs]` 依赖项 | +| Docker | 新的容器镜像 | +| 流程定义 | 将通用解码器设置为文档输入 | + +### 未变更的内容 + +- 分块器(接收 `TextDocument`,行为与之前相同) +- 下游提取器(接收 `Chunk`,未发生变化) +- 库管理员(存储子文档,未发生变化) +- 模式(`Document`、`TextDocument`、`Chunk` 未发生变化) +- 查询时溯源(未发生变化) + +## 风险 + +- `unstructured[all-docs]` 具有大量的依赖项(包括 poppler、tesseract 和 libreoffice,用于某些格式)。容器镜像会更大。 + 缓解措施:提供不包含 OCR/办公室依赖项的 `[light]` 版本。 +- 某些格式可能导致文本提取效果不佳(扫描的 PDF 文件缺少 OCR,复杂的 XLSX 布局)。 + 缓解措施:配置 `strategy` 参数,并且现有的 Mistral OCR 解码器仍然可用于高质量的 PDF OCR。 +- `unstructured` 版本更新可能会更改元素元数据。 + 缓解措施:固定版本,并为每个格式测试提取质量。 \ No newline at end of file diff --git a/generate_i18n_packs.py b/generate_i18n_packs.py new file mode 100644 index 00000000..a379efb2 --- /dev/null +++ b/generate_i18n_packs.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python3 + +"""Generate TrustGraph pre-built language packs using the local Ollama translate model. + +This script translates a curated set of UI/CLI strings (keys) from English into +all supported languages and writes JSON packs under: + trustgraph-base/trustgraph/i18n/packs/ + +Design goal: no runtime translation. Packs are generated ahead of time and +loaded via `trustgraph.i18n`. + +Requires: +- Ollama running locally (default: http://localhost:11434) +- Model available (default: translategemma:12b) + +Usage: + python generate_i18n_packs.py + +You can override: + OLLAMA_URL, OLLAMA_MODEL +""" + +from __future__ import annotations + +import argparse +import json +import os +import re +from pathlib import Path +from typing import Dict, List, Tuple + +# Reuse the hardened translation engine we already use for docs. +import translate_docs + + +DEFAULT_OUTPUT_DIR = Path("trustgraph-base/trustgraph/i18n/packs") + +# 10 languages (including English) +LANGS: Dict[str, Tuple[str, str]] = { + "en": ("English", "en"), + "es": ("Spanish", "es"), + "sw": ("Swahili", "sw"), + "pt": ("Portuguese", "pt"), + "tr": ("Turkish", "tr"), + "hi": ("Hindi", "hi"), + "he": ("Hebrew", "he"), + "ar": ("Arabic", "ar"), + "zh-cn": ("Chinese (simplified)", "zh-cn"), + "ru": ("Russian", "ru"), +} + + +# Curated strings currently used by tg-verify-system-status. +# Keep keys stable. +EN_STRINGS: Dict[str, str] = { + "cli.verify_system_status.title": "TrustGraph System Status Verification", + "cli.verify_system_status.phase_1": "Phase 1: Infrastructure", + "cli.verify_system_status.phase_2": "Phase 2: Core Services", + "cli.verify_system_status.phase_3": "Phase 3: Data Services", + "cli.verify_system_status.phase_4": "Phase 4: User Interface", + "cli.verify_system_status.summary": "Summary", + "cli.verify_system_status.checking": "Checking {name}...", + "cli.verify_system_status.checking_attempt": "Checking {name}... (attempt {attempt})", + "cli.verify_system_status.failed_timeout": "{name}: Failed (timeout after {attempt} attempts)", + "cli.verify_system_status.pulsar_not_responding": "Pulsar is not responding - other checks may fail", + "cli.verify_system_status.checks_passed": "Checks passed: {passed}/{total}", + "cli.verify_system_status.checks_failed": "Checks failed: {failed}/{total}", + "cli.verify_system_status.total_time": "Total time: {elapsed}", + "cli.verify_system_status.system_healthy": "System is healthy!", + "cli.verify_system_status.system_failing": "System has {failed} failing check(s)", + + "cli.verify_system_status.check_name.pulsar": "Pulsar", + "cli.verify_system_status.check_name.api_gateway": "API Gateway", + "cli.verify_system_status.check_name.processors": "Processors", + "cli.verify_system_status.check_name.flow_blueprints": "Flow Blueprints", + "cli.verify_system_status.check_name.flows": "Flows", + "cli.verify_system_status.check_name.prompts": "Prompts", + "cli.verify_system_status.check_name.library": "Library", + "cli.verify_system_status.check_name.workbench_ui": "Workbench UI", + + "cli.verify_system_status.pulsar.healthy": "Pulsar healthy ({clusters} cluster(s))", + "cli.verify_system_status.pulsar.status": "Pulsar returned status {status_code}", + "cli.verify_system_status.pulsar.timeout": "Pulsar connection timeout", + "cli.verify_system_status.pulsar.cannot_connect": "Cannot connect to Pulsar", + "cli.verify_system_status.pulsar.error": "Pulsar error: {error}", + + "cli.verify_system_status.api_gateway.responding": "API Gateway is responding", + "cli.verify_system_status.api_gateway.status": "API Gateway returned status {status_code}", + "cli.verify_system_status.api_gateway.timeout": "API Gateway connection timeout", + "cli.verify_system_status.api_gateway.cannot_connect": "Cannot connect to API Gateway", + "cli.verify_system_status.api_gateway.error": "API Gateway error: {error}", + + "cli.verify_system_status.processors.found": "Found {count} processors (≥ {min})", + "cli.verify_system_status.processors.only": "Only {count} processors running (need {min})", + "cli.verify_system_status.processors.metrics_status": "Metrics returned status {status_code}", + "cli.verify_system_status.processors.error": "Processor check error: {error}", + + "cli.verify_system_status.flow_blueprints.found": "Found {count} flow blueprint(s)", + "cli.verify_system_status.flow_blueprints.none": "No flow blueprints found", + "cli.verify_system_status.flow_blueprints.error": "Flow blueprints check error: {error}", + + "cli.verify_system_status.flows.responding": "Flow manager responding ({count} flow(s))", + "cli.verify_system_status.flows.error": "Flow manager check error: {error}", + + "cli.verify_system_status.prompts.found": "Found {count} prompt(s)", + "cli.verify_system_status.prompts.none": "No prompts found", + "cli.verify_system_status.prompts.error": "Prompts check error: {error}", + + "cli.verify_system_status.library.responding": "Library responding ({count} document(s))", + "cli.verify_system_status.library.error": "Library check error: {error}", + + "cli.verify_system_status.ui.responding": "Workbench UI is responding", + "cli.verify_system_status.ui.status": "UI returned status {status_code}", + "cli.verify_system_status.ui.timeout": "UI connection timeout", + "cli.verify_system_status.ui.cannot_connect": "Cannot connect to UI", + "cli.verify_system_status.ui.error": "UI error: {error}", +} + + +_FMT_RE = re.compile(r"\{[a-zA-Z0-9_]+\}") + + +def _protect_format_placeholders(text: str) -> Tuple[str, Dict[str, str]]: + """Replace `{name}` placeholders with CODE-like placeholders that the doc translator preserves.""" + + mapping: Dict[str, str] = {} + + def repl(m: re.Match[str]) -> str: + idx = len(mapping) + token = f"⟦CODE_{idx}⟧" + mapping[token] = m.group(0) + return token + + protected = _FMT_RE.sub(repl, text) + return protected, mapping + + +def _restore_format_placeholders(text: str, mapping: Dict[str, str]) -> str: + out = text + for token, original in mapping.items(): + out = out.replace(token, original) + return out + + +def _validate_placeholders(restored: str, originals: List[str]) -> bool: + return all(ph in restored for ph in originals) + + +def translate_pack(client: translate_docs.OllamaClient, *, lang_name: str, lang_code: str) -> Dict[str, str]: + keys = list(EN_STRINGS.keys()) + + protected_lines: List[str] = [] + placeholder_maps: List[Dict[str, str]] = [] + placeholder_originals: List[List[str]] = [] + + for k in keys: + text = EN_STRINGS[k] + protected, mapping = _protect_format_placeholders(text) + protected_lines.append(protected + "\n") + placeholder_maps.append(mapping) + placeholder_originals.append(list(mapping.values())) + + translated = translate_docs.translate_lines_resilient( + client, + lines=protected_lines, + target_language_name=lang_name, + target_language_code=lang_code, + retries=2, + ) + + if translated is None: + raise RuntimeError(f"Translation failed for {lang_code}") + + out_lines = translated.splitlines() + if len(out_lines) != len(keys): + raise RuntimeError(f"Unexpected line count for {lang_code}: {len(out_lines)} != {len(keys)}") + + pack: Dict[str, str] = {} + for i, k in enumerate(keys): + restored = _restore_format_placeholders(out_lines[i], placeholder_maps[i]) + + # Ensure python-format placeholders survived + if not _validate_placeholders(restored, placeholder_originals[i]): + raise RuntimeError(f"Placeholder lost for key {k} in {lang_code}") + + pack[k] = restored + + return pack + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--output-dir", + default=str(DEFAULT_OUTPUT_DIR), + help=f"Output directory for packs (default: {DEFAULT_OUTPUT_DIR})", + ) + + args = parser.parse_args() + + output_dir = Path(args.output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + + client = translate_docs.OllamaClient( + url=os.getenv("OLLAMA_URL", translate_docs.DEFAULT_OLLAMA_URL), + model=os.getenv("OLLAMA_MODEL", translate_docs.DEFAULT_OLLAMA_MODEL), + num_ctx=translate_docs.DEFAULT_NUM_CTX, + num_predict=translate_docs.DEFAULT_NUM_PREDICT, + temperature=translate_docs.DEFAULT_TEMPERATURE, + top_p=translate_docs.DEFAULT_TOP_P, + repeat_penalty=translate_docs.DEFAULT_REPEAT_PENALTY, + keep_alive=translate_docs.DEFAULT_KEEP_ALIVE, + ) + + # Always write English as the source pack + (output_dir / "en.json").write_text(json.dumps(EN_STRINGS, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + + for lang, (name, code) in LANGS.items(): + if lang == "en": + continue + + print(f"\n=== Generating pack: {lang} ({name}) ===") + pack = translate_pack(client, lang_name=name, lang_code=code) + (output_dir / f"{lang}.json").write_text( + json.dumps(pack, ensure_ascii=False, indent=2) + "\n", + encoding="utf-8", + ) + + print("\nDone.") + + +if __name__ == "__main__": + main() diff --git a/tests/conftest.py b/tests/conftest.py index 7c6ffc13..6f63967c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,6 +8,7 @@ import pytest # import asyncio # import tracemalloc # import warnings +import logging from unittest.mock import MagicMock # Uncomment the lines below to enable asyncio debug mode and tracemalloc @@ -33,19 +34,14 @@ def mock_loki_handler(session_mocker=None): # Create a mock LokiHandler that does nothing original_loki_handler = logging_loki.LokiHandler - class MockLokiHandler: + class MockLokiHandler(logging.Handler): """Mock LokiHandler that doesn't make network calls.""" + def __init__(self, *args, **kwargs): - pass + super().__init__() def emit(self, record): - pass - - def flush(self): - pass - - def close(self): - pass + return # Replace the real LokiHandler with our mock logging_loki.LokiHandler = MockLokiHandler diff --git a/tests/unit/test_base/test_i18n.py b/tests/unit/test_base/test_i18n.py new file mode 100644 index 00000000..2d357a1d --- /dev/null +++ b/tests/unit/test_base/test_i18n.py @@ -0,0 +1,40 @@ +from trustgraph.i18n import get_language_pack, get_translator, normalize_language + + +def test_normalize_language_handles_regions_and_accept_language(): + assert normalize_language(None) == "en" + assert normalize_language("") == "en" + + assert normalize_language("es-ES") == "es" + assert normalize_language("pt-BR") == "pt" + assert normalize_language("zh") == "zh-cn" + + assert normalize_language("es-ES,es;q=0.9,en;q=0.8") == "es" + assert normalize_language("unknown") == "en" + + +def test_language_pack_loads_from_resources(): + pack = get_language_pack("en") + assert isinstance(pack, dict) + + # Key should exist and map to a non-empty string. + title = pack.get("cli.verify_system_status.title") + assert isinstance(title, str) + assert title.strip() != "" + + +def test_translator_formats_placeholders(): + tr = get_translator("en") + out = tr.t( + "cli.verify_system_status.checking_attempt", + name="Pulsar", + attempt=2, + ) + + assert "Pulsar" in out + assert "2" in out + + +def test_translator_falls_back_to_key_for_unknown_keys(): + tr = get_translator("en") + assert tr.t("missing.key") == "missing.key" diff --git a/tests/unit/test_gateway/test_endpoint_i18n.py b/tests/unit/test_gateway/test_endpoint_i18n.py new file mode 100644 index 00000000..ab693cdf --- /dev/null +++ b/tests/unit/test_gateway/test_endpoint_i18n.py @@ -0,0 +1,75 @@ +"""Tests for Gateway i18n pack endpoint.""" + +import json +from unittest.mock import MagicMock + +import pytest +from aiohttp import web + +from trustgraph.gateway.endpoint.i18n import I18nPackEndpoint + + +class TestI18nPackEndpoint: + + def test_i18n_endpoint_initialization(self): + mock_auth = MagicMock() + + endpoint = I18nPackEndpoint( + endpoint_path="/api/v1/i18n/packs/{lang}", + auth=mock_auth, + ) + + assert endpoint.path == "/api/v1/i18n/packs/{lang}" + assert endpoint.auth == mock_auth + assert endpoint.operation == "service" + + @pytest.mark.asyncio + async def test_i18n_endpoint_start_method(self): + mock_auth = MagicMock() + endpoint = I18nPackEndpoint("/api/v1/i18n/packs/{lang}", mock_auth) + await endpoint.start() + + def test_add_routes_registers_get_handler(self): + mock_auth = MagicMock() + mock_app = MagicMock() + + endpoint = I18nPackEndpoint("/api/v1/i18n/packs/{lang}", mock_auth) + endpoint.add_routes(mock_app) + + mock_app.add_routes.assert_called_once() + call_args = mock_app.add_routes.call_args[0][0] + assert len(call_args) == 1 + + @pytest.mark.asyncio + async def test_handle_unauthorized_on_invalid_auth_scheme(self): + mock_auth = MagicMock() + mock_auth.permitted.return_value = True + + endpoint = I18nPackEndpoint("/api/v1/i18n/packs/{lang}", mock_auth) + + request = MagicMock() + request.path = "/api/v1/i18n/packs/en" + request.headers = {"Authorization": "Token abc"} + request.match_info = {"lang": "en"} + + resp = await endpoint.handle(request) + assert isinstance(resp, web.HTTPUnauthorized) + + @pytest.mark.asyncio + async def test_handle_returns_pack_when_permitted(self): + mock_auth = MagicMock() + mock_auth.permitted.return_value = True + + endpoint = I18nPackEndpoint("/api/v1/i18n/packs/{lang}", mock_auth) + + request = MagicMock() + request.path = "/api/v1/i18n/packs/en" + request.headers = {} + request.match_info = {"lang": "en"} + + resp = await endpoint.handle(request) + + assert resp.status == 200 + payload = json.loads(resp.body.decode("utf-8")) + assert isinstance(payload, dict) + assert "cli.verify_system_status.title" in payload diff --git a/translate_docs.py b/translate_docs.py old mode 100644 new mode 100755 index f13eaea3..b814e010 --- a/translate_docs.py +++ b/translate_docs.py @@ -1,71 +1,824 @@ -import os -import requests +import argparse import glob +import json +import math +import os +import re +import sys +from dataclasses import dataclass from pathlib import Path +from typing import Dict, Iterable, List, Optional, Sequence, Tuple -# Configuration -OLLAMA_URL = "http://localhost:11434/api/generate" -OLLAMA_MODEL = "translategemma:12b" # CHANGE THIS to your preferred local model (e.g., 'mistral', 'llama3', 'qwen') +import requests -LANGUAGES = { + +# ---------------------------- +# Defaults / configuration +# ---------------------------- + +DEFAULT_OLLAMA_URL = os.getenv("OLLAMA_URL", "http://localhost:11434/api/generate") +DEFAULT_OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "translategemma:12b") +DEFAULT_DOCS_DIR = os.getenv("DOCS_DIR", "docs/tech-specs") + +# With chunked translation, a smaller ctx is usually faster and more reliable. +DEFAULT_NUM_CTX = int(os.getenv("OLLAMA_NUM_CTX", "4096")) + +# Critical: many incomplete translations come from low/default num_predict. +DEFAULT_NUM_PREDICT = int(os.getenv("OLLAMA_NUM_PREDICT", "4096")) + +DEFAULT_TEMPERATURE = float(os.getenv("OLLAMA_TEMPERATURE", "0.1")) +DEFAULT_TOP_P = float(os.getenv("OLLAMA_TOP_P", "0.9")) +DEFAULT_REPEAT_PENALTY = float(os.getenv("OLLAMA_REPEAT_PENALTY", "1.1")) + +DEFAULT_KEEP_ALIVE = os.getenv("OLLAMA_KEEP_ALIVE", "15m") + +DEFAULT_CONNECT_TIMEOUT = int(os.getenv("OLLAMA_CONNECT_TIMEOUT", "30")) +# If Ollama stops streaming mid-response, we want to recover quickly. +# This is a *per-socket-read* timeout (it resets whenever a chunk arrives). +DEFAULT_READ_TIMEOUT = int(os.getenv("OLLAMA_READ_TIMEOUT", "180")) + +DEFAULT_MAX_CHUNK_LINES = int(os.getenv("TG_TRANSLATE_MAX_CHUNK_LINES", "200")) +DEFAULT_MAX_CHUNK_CHARS = int(os.getenv("TG_TRANSLATE_MAX_CHUNK_CHARS", "12000")) +DEFAULT_RETRIES = int(os.getenv("TG_TRANSLATE_RETRIES", "2")) + +LANGUAGES: Dict[str, str] = { "Spanish": "es", "Swahili": "sw", + "Portuguese": "pt", + "Turkish": "tr", "Hindi": "hi", "Hebrew": "he", "Arabic": "ar", "Chinese (simplified)": "zh-cn", - "Russian": "ru" + "Russian": "ru", } -DOCS_DIR = "docs/tech-specs" -def translate_text(text, target_language): - prompt = f"""Translate the following documentation into {target_language}. -CRITICAL INSTRUCTIONS: -- Provide a STRICT 1:1 translation. Every sentence of the provided text MUST be translated. -- You MUST use the native and correct alphabet/script for the target language (e.g., Cyrillic for Russian, Arabic script for Arabic, Devanagari for Hindi, Hebrew script for Hebrew, Simplified Chinese for Chinese). Swahili and Spanish use the Latin alphabet. -- Preserve ALL Markdown formatting, headers, links, and HTML tags precisely. -- Do NOT translate code inside backticks or code blocks. -- Output ONLY the translated text without any conversational preamble or explanations. +# ---------------------------- +# Markdown splitting helpers +# ---------------------------- -Text to translate: -{text}""" - - payload = { - "model": OLLAMA_MODEL, - "prompt": prompt, - "stream": False - } - - try: - # Reduced timeout to 180 seconds (3 minutes) to prevent endless freezing - response = requests.post(OLLAMA_URL, json=payload, timeout=180) - response.raise_for_status() - return response.json().get("response", "").strip() - except requests.exceptions.Timeout: - print(f" [!] Translation timed out (took longer than 3 minutes). Skipping to next.") - return None - except requests.exceptions.RequestException as e: - print(f" [!] Failed to connect to Ollama or process translation: {e}") + +@dataclass(frozen=True) +class Block: + kind: str # "text" | "code" + lines: List[str] # each element includes its original newline (if present) + + +FENCE_RE = re.compile(r"^[ \t]*(```+|~~~+)") + + +def _split_line_ending(line: str) -> Tuple[str, str]: + if line.endswith("\r\n"): + return line[:-2], "\r\n" + if line.endswith("\n"): + return line[:-1], "\n" + return line, "" + + +def split_markdown_blocks(text: str) -> List[Block]: + lines = text.splitlines(keepends=True) + if not lines: + return [Block(kind="text", lines=[])] + + blocks: List[Block] = [] + + # YAML front-matter: treat as non-translatable. + idx = 0 + if lines and lines[0].strip() == "---": + for j in range(1, len(lines)): + if lines[j].strip() in {"---", "..."}: + blocks.append(Block(kind="code", lines=lines[: j + 1])) + idx = j + 1 + break + + current: List[str] = [] + in_fence = False + fence_marker: Optional[str] = None + fence_len = 0 + + def flush(kind: str) -> None: + nonlocal current + if current: + blocks.append(Block(kind=kind, lines=current)) + current = [] + + for line in lines[idx:]: + m = FENCE_RE.match(line) + if m: + marker = m.group(1) + if not in_fence: + flush("text") + in_fence = True + fence_marker = marker[0:3] + fence_len = len(marker) + current.append(line) + continue + + # Close if same fence char and len >= opener len + if fence_marker and marker.startswith(fence_marker) and len(marker) >= fence_len: + current.append(line) + flush("code") + in_fence = False + fence_marker = None + fence_len = 0 + continue + + current.append(line) + + flush("code" if in_fence else "text") + return blocks + + +def chunk_lines(lines: Sequence[str], *, max_lines: int, max_chars: int) -> List[List[str]]: + """Split lines into reasonably-sized chunks. + + This prefers breaking at safe Markdown boundaries (blank lines, headings, rules) + so the model stays focused and is less likely to drift. + """ + + def is_good_break(line: str) -> bool: + s = line.strip() + if s == "": + return True + if s.startswith("#"): + return True + if s in {"---", "***", "___"}: + return True + return False + + chunks: List[List[str]] = [] + n = len(lines) + start = 0 + + while start < n: + end = start + cur_chars = 0 + last_good_end: Optional[int] = None + + while end < n: + line_len = len(lines[end]) + + # Ensure progress even if a single line exceeds max_chars. + if end == start and line_len > max_chars: + end += 1 + last_good_end = end + break + + if (end - start) >= max_lines: + break + if (cur_chars + line_len) > max_chars: + break + + cur_chars += line_len + end += 1 + if is_good_break(lines[end - 1]): + last_good_end = end + + if end >= n: + chunks.append(list(lines[start:end])) + break + + cut = last_good_end if (last_good_end is not None and last_good_end > start) else end + if cut <= start: + cut = min(start + 1, n) + + chunks.append(list(lines[start:cut])) + start = cut + + return chunks + + +# ---------------------------- +# Ollama client +# ---------------------------- + + +class OllamaClient: + def __init__( + self, + *, + url: str, + model: str, + num_ctx: int, + num_predict: int, + temperature: float, + top_p: float, + repeat_penalty: float, + keep_alive: str, + timeout: Tuple[int, int] = (DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT), + ) -> None: + self.url = url + self.model = model + self.num_ctx = num_ctx + self.num_predict = num_predict + self.temperature = temperature + self.top_p = top_p + self.repeat_penalty = repeat_penalty + self.keep_alive = keep_alive + self.timeout = timeout + self.session = requests.Session() + + def reset_session(self) -> None: + try: + self.session.close() + except Exception: + pass + self.session = requests.Session() + + def generate( + self, + *, + prompt: str, + system: Optional[str] = None, + stop: Optional[List[str]] = None, + progress_dots: bool = False, + ) -> str: + payload: Dict[str, object] = { + "model": self.model, + "prompt": prompt, + "stream": True, + "keep_alive": self.keep_alive, + "options": { + "num_ctx": self.num_ctx, + "num_predict": self.num_predict, + "temperature": self.temperature, + "top_p": self.top_p, + "repeat_penalty": self.repeat_penalty, + }, + } + if system: + payload["system"] = system + if stop: + payload["options"]["stop"] = stop + + out: List[str] = [] + stream_error: Optional[str] = None + dot_counter = 0 + + # Ensure we always release the connection back to the pool. + with self.session.post(self.url, json=payload, stream=True, timeout=self.timeout) as response: + response.raise_for_status() + + for raw in response.iter_lines(): + if not raw: + continue + try: + chunk = json.loads(raw) + except json.JSONDecodeError: + continue + + if "error" in chunk and chunk["error"]: + stream_error = str(chunk["error"]) + break + + piece = chunk.get("response") + if piece: + out.append(piece) + if progress_dots: + dot_counter += 1 + if dot_counter % 50 == 0: + sys.stdout.write(".") + sys.stdout.flush() + if chunk.get("done") is True: + break + + if stream_error: + raise requests.exceptions.RequestException(f"Ollama error: {stream_error}") + + result = "".join(out) + if result == "": + raise requests.exceptions.RequestException("Empty response from Ollama") + return result + + +# ---------------------------- +# Translation (validated, line-indexed) +# ---------------------------- + + +INLINE_CODE_RE = re.compile(r"`[^`]*`") +URL_RE = re.compile(r"https?://[^\s)>]+") +# Some models occasionally insert leading whitespace or a colon after the prefix. +PREFIX_RE = re.compile(r"^\s*\[\[(\d+)\]\]\s*[:\-]?\s*(.*)$") + + +def _protect_spans(text: str) -> Tuple[str, Dict[str, str]]: + """Protect inline code spans and URLs with placeholders that must be kept verbatim.""" + placeholders: Dict[str, str] = {} + + def repl_code(m: re.Match) -> str: + key = f"⟦CODE_{len(placeholders)}⟧" + placeholders[key] = m.group(0) + return key + + def repl_url(m: re.Match) -> str: + key = f"⟦URL_{len(placeholders)}⟧" + placeholders[key] = m.group(0) + return key + + text = INLINE_CODE_RE.sub(repl_code, text) + text = URL_RE.sub(repl_url, text) + return text, placeholders + + +def _restore_spans(text: str, placeholders: Dict[str, str]) -> str: + for key, original in placeholders.items(): + text = text.replace(key, original) + return text + + +def _build_numbered_input(lines: Sequence[str]) -> Tuple[str, List[Tuple[str, str, str, Dict[str, str]]]]: + """Return (prompt_text, meta) where meta items are (leading_ws, newline, original_empty_marker, placeholders).""" + meta: List[Tuple[str, str, str, Dict[str, str]]] = [] + width = max(4, len(str(len(lines)))) + numbered: List[str] = [] + + for i, line in enumerate(lines, start=1): + content, newline = _split_line_ending(line) + leading_ws = re.match(r"^[\t ]*", content).group(0) + rest = content[len(leading_ws) :] + + protected, placeholders = _protect_spans(rest) + + prefix = f"[[{i:0{width}d}]]" + # NOTE: we do NOT send leading whitespace to the model; we reattach it to keep indentation exact. + numbered.append(f"{prefix} {protected}") + meta.append((leading_ws, newline, "", placeholders)) + + return "\n".join(numbered), meta + + +def _parse_numbered_output(output: str) -> Dict[int, str]: + parsed: Dict[int, str] = {} + for raw_line in output.splitlines(): + m = PREFIX_RE.match(raw_line.strip("\r")) + if not m: + continue + idx = int(m.group(1)) + parsed[idx] = m.group(2) + return parsed + + +def _find_missing_indices(parsed: Dict[int, str], expected: int) -> List[int]: + return [i for i in range(1, expected + 1) if i not in parsed] + + +def _repair_missing_numbered_lines( + client: OllamaClient, + *, + missing_numbered_lines: Sequence[str], + target_language_name: str, + target_language_code: str, + sentinel: str, +) -> Dict[int, str]: + """Ask the model to translate only the missing numbered lines.""" + system = ( + "You are a meticulous translation engine. " + "Never summarize, never omit content, and never add commentary. " + "Follow the output format exactly." + ) + + prompt = ( + f"Translate ONLY the following missing Markdown lines into {target_language_name} ({target_language_code}).\n" + "\n" + "OUTPUT CONTRACT (must follow exactly):\n" + "- Output ONLY the translated lines for the provided [[NNNN]] prefixes.\n" + "- Preserve Markdown syntax exactly.\n" + "- Do NOT translate placeholders like ⟦CODE_0⟧ or ⟦URL_0⟧; keep them exactly unchanged.\n" + "- Do NOT add any additional lines or prefixes beyond those provided.\n" + "- Do NOT wrap the output in code fences.\n" + f"- After the last translated line, output a final line containing exactly: {sentinel}\n" + "\n" + "MISSING INPUT LINES:\n" + + "\n".join(missing_numbered_lines) + + "\n" + ) + + # Keep CLI output clean: the main generation already shows progress dots. + raw = client.generate(prompt=prompt, system=system, stop=["\n" + sentinel], progress_dots=False) + return _parse_numbered_output(raw) + + +def translate_lines_strict( + client: OllamaClient, + *, + lines: Sequence[str], + target_language_name: str, + target_language_code: str, + retries: int, +) -> Optional[str]: + """Translate the given lines (including newlines) and return the translated text for this chunk.""" + numbered_input, meta = _build_numbered_input(lines) + expected = len(lines) + sentinel = "[[__END_OF_TRANSLATION__]]" + + system = ( + "You are a meticulous translation engine. " + "Never summarize, never omit content, and never add commentary. " + "Follow the output format exactly." + ) + + prompt = ( + f"Translate the following Markdown lines into {target_language_name} ({target_language_code}).\n" + "\n" + "OUTPUT CONTRACT (must follow exactly):\n" + "- Translate EVERY line; do not omit, reorder, merge, or split lines.\n" + "- Preserve Markdown syntax exactly (headings, bullets, tables, links, HTML tags).\n" + "- Do NOT translate placeholders like ⟦CODE_0⟧ or ⟦URL_0⟧; keep them exactly unchanged.\n" + "- Return ONLY translated lines, each starting with its original [[NNNN]] prefix.\n" + "- Do NOT wrap the output in code fences.\n" + "- Do NOT add blank lines between numbered lines.\n" + f"- After the last line, output a final line containing exactly: {sentinel}\n" + "\n" + "EXAMPLE FORMAT (illustrative):\n" + "INPUT:\n" + "[[0001]] Example line\n" + "[[0002]] Another line\n" + "OUTPUT:\n" + "[[0001]] \n" + "[[0002]] \n" + f"{sentinel}\n" + "\n" + "INPUT LINES:\n" + f"{numbered_input}\n" + ) + + last_error: Optional[str] = None + for attempt in range(retries + 1): + try: + sys.stdout.write(" [Generating]") + sys.stdout.flush() + raw = client.generate(prompt=prompt, system=system, stop=["\n" + sentinel], progress_dots=True) + sys.stdout.write(" Done!\n") + except requests.exceptions.Timeout: + sys.stdout.write(" Timeout!\n") + last_error = "timeout" + client.reset_session() + continue + except requests.exceptions.RequestException as e: + sys.stdout.write(" Failed!\n") + last_error = str(e) + client.reset_session() + continue + + parsed = _parse_numbered_output(raw) + # Ignore harmless extra indices if the model repeats itself. + parsed = {i: v for i, v in parsed.items() if 1 <= i <= expected} + + missing = _find_missing_indices(parsed, expected) + if missing: + # Fast path: repair only a small number of missing lines. + # This avoids re-translating large chunks when we only missed a couple of prefixes. + if len(missing) <= min(12, max(3, expected // 10)): + numbered_lines = numbered_input.splitlines() + if len(numbered_lines) == expected: + missing_input = [numbered_lines[i - 1] for i in missing] + try: + repaired = _repair_missing_numbered_lines( + client, + missing_numbered_lines=missing_input, + target_language_name=target_language_name, + target_language_code=target_language_code, + sentinel=sentinel, + ) + repaired = {i: v for i, v in repaired.items() if i in missing} + parsed.update(repaired) + missing = _find_missing_indices(parsed, expected) + except requests.exceptions.Timeout: + client.reset_session() + except requests.exceptions.RequestException: + client.reset_session() + + if missing: + last_error = f"missing lines ({expected - len(missing)}/{expected})" + # Let the caller split smaller rather than retrying the same large prompt. + break + + # Validate that protected placeholders were preserved. + placeholder_missing = 0 + for i in range(1, expected + 1): + _leading_ws, _newline, _unused, placeholders = meta[i - 1] + if not placeholders: + continue + out_line = parsed.get(i, "") + for key in placeholders.keys(): + if key not in out_line: + placeholder_missing += 1 + if placeholder_missing: + last_error = f"placeholder lost ({placeholder_missing})" + break + + # Reconstruct chunk, preserving indentation + original newlines. + out_lines: List[str] = [] + for i in range(1, expected + 1): + leading_ws, newline, _unused, placeholders = meta[i - 1] + translated_rest = parsed[i] + translated_rest = _restore_spans(translated_rest, placeholders) + out_lines.append(leading_ws + translated_rest + newline) + + return "".join(out_lines) + + print(f" [!] Chunk translation failed after retries: {last_error}") + return None + + +def _is_good_split_boundary(line: str) -> bool: + s = line.strip() + if s == "": + return True + if s.startswith("#"): + return True + if s in {"---", "***", "___"}: + return True + return False + + +def _find_best_split_index(lines: Sequence[str]) -> int: + """Pick a split point near the middle, preferably after a safe Markdown boundary.""" + n = len(lines) + if n <= 1: + return 1 + + mid = n // 2 + candidates: List[int] = [] + for i in range(1, n): + if _is_good_split_boundary(lines[i - 1]): + candidates.append(i) + if not candidates: + return mid + + return min(candidates, key=lambda i: abs(i - mid)) + + +def translate_single_line_fallback( + client: OllamaClient, + *, + line: str, + target_language_name: str, + target_language_code: str, + retries: int, +) -> Optional[str]: + """Last-resort translation for one line when the numbered contract keeps failing.""" + content, newline = _split_line_ending(line) + leading_ws = re.match(r"^[\t ]*", content).group(0) + rest = content[len(leading_ws) :] + + # Empty/whitespace lines: keep as-is. + if rest.strip() == "": + return line + + protected, placeholders = _protect_spans(rest) + + system = ( + "You are a meticulous translation engine. " + "Never summarize, never omit content, and never add commentary." + ) + + prompt = ( + f"Translate this SINGLE Markdown line into {target_language_name} ({target_language_code}).\n" + "Rules:\n" + "- Output EXACTLY one line (no surrounding quotes, no code fences, no prefixes).\n" + "- Preserve Markdown punctuation exactly (e.g., `#`, `-`, `*`, `|`, links).\n" + "- Do NOT translate placeholders like ⟦CODE_0⟧ or ⟦URL_0⟧; keep them unchanged.\n" + "- Do NOT add explanations.\n" + "\n" + f"LINE: {protected}\n" + ) + + last_error: Optional[str] = None + for _attempt in range(retries + 1): + try: + raw = client.generate(prompt=prompt, system=system) + except requests.exceptions.Timeout: + last_error = "timeout" + client.reset_session() + continue + except requests.exceptions.RequestException as e: + last_error = str(e) + client.reset_session() + continue + + candidate = raw.strip("\r\n") + if "\n" in candidate: + candidate = candidate.splitlines()[0] + candidate = candidate.strip() + if not candidate: + last_error = "empty response" + continue + + # Ensure placeholders survive for inline code/URLs. + for key in placeholders.keys(): + if key not in candidate: + last_error = "placeholder lost" + candidate = "" + break + if candidate == "": + continue + + candidate = _restore_spans(candidate, placeholders) + return leading_ws + candidate + newline + + print(f" [!] Single-line fallback failed: {last_error}") + return None + + +def translate_lines_resilient( + client: OllamaClient, + *, + lines: Sequence[str], + target_language_name: str, + target_language_code: str, + retries: int, + split_budget: Optional[int] = None, +) -> Optional[str]: + """Translate lines, automatically splitting smaller if the strict contract fails. + + This prevents a single bad chunk from failing an entire language run. + """ + if not lines: + return "" + + # Adaptive budget: ensure we can always reach single-line fallback when needed. + if split_budget is None: + # Depth to reach 1 line by halving: ceil(log2(n)). Add a small buffer. + split_budget = max(6, int(math.ceil(math.log2(len(lines)))) + 2) + + translated = translate_lines_strict( + client, + lines=lines, + target_language_name=target_language_name, + target_language_code=target_language_code, + retries=retries, + ) + if translated is not None: + return translated + + if len(lines) == 1: + return translate_single_line_fallback( + client, + line=lines[0], + target_language_name=target_language_name, + target_language_code=target_language_code, + retries=retries, + ) + + if split_budget <= 0: return None -def main(): - # Find all English markdown and html files in docs folder - # Assuming original files don't have language suffixes - files = [] - for ext in ['*.md']: - for path in glob.glob(os.path.join(DOCS_DIR, ext)): + split_at = _find_best_split_index(lines) + left = translate_lines_resilient( + client, + lines=lines[:split_at], + target_language_name=target_language_name, + target_language_code=target_language_code, + retries=retries, + split_budget=split_budget - 1, + ) + if left is None: + return None + + right = translate_lines_resilient( + client, + lines=lines[split_at:], + target_language_name=target_language_name, + target_language_code=target_language_code, + retries=retries, + split_budget=split_budget - 1, + ) + if right is None: + return None + + return left + right + + +def translate_markdown_document( + client: OllamaClient, + *, + content: str, + target_language_name: str, + target_language_code: str, + max_chunk_lines: int, + max_chunk_chars: int, + retries: int, +) -> Optional[str]: + blocks = split_markdown_blocks(content) + out_parts: List[str] = [] + + for block in blocks: + if block.kind == "code": + out_parts.append("".join(block.lines)) + continue + + # chunk and translate + for chunk in chunk_lines(block.lines, max_lines=max_chunk_lines, max_chars=max_chunk_chars): + translated = translate_lines_resilient( + client, + lines=chunk, + target_language_name=target_language_name, + target_language_code=target_language_code, + retries=retries, + ) + if translated is None: + return None + out_parts.append(translated) + + return "".join(out_parts) + + +def looks_incomplete(existing_translation: str, source: str) -> bool: + """Conservative heuristic to detect summaries/truncation in already-generated files.""" + if not existing_translation.strip(): + return True + + src_len = len(source.strip()) + out_len = len(existing_translation.strip()) + if src_len >= 2000 and out_len < int(src_len * 0.35): + return True + + src_lines = len([l for l in source.splitlines() if l.strip()]) + out_lines = len([l for l in existing_translation.splitlines() if l.strip()]) + if src_lines >= 80 and out_lines < int(src_lines * 0.45): + return True + + # Obvious “assistant” preambles. + lowered = existing_translation.lstrip().lower() + if lowered.startswith("sure") or lowered.startswith("here is") or "summary" in lowered[:200]: + return True + + return False + + +# ---------------------------- +# CLI / main +# ---------------------------- + + +def _parse_langs(arg: Optional[str]) -> Dict[str, str]: + if not arg: + return dict(LANGUAGES) + + wanted = {a.strip().lower() for a in arg.split(",") if a.strip()} + resolved: Dict[str, str] = {} + + for name, code in LANGUAGES.items(): + if name.lower() in wanted or code.lower() in wanted: + resolved[name] = code + + unknown = wanted - {n.lower() for n in LANGUAGES.keys()} - {c.lower() for c in LANGUAGES.values()} + if unknown: + raise SystemExit(f"Unknown languages: {', '.join(sorted(unknown))}") + return resolved + + +def main() -> None: + parser = argparse.ArgumentParser(description="Translate docs/tech-specs markdown files using a local Ollama model.") + parser.add_argument("--docs-dir", default=DEFAULT_DOCS_DIR, help="Directory containing source .md files") + parser.add_argument("--model", default=DEFAULT_OLLAMA_MODEL, help="Ollama model name") + parser.add_argument("--ollama-url", default=DEFAULT_OLLAMA_URL, help="Ollama /api/generate URL") + parser.add_argument("--langs", default=None, help="Comma-separated language names or codes (e.g. 'es,ru')") + parser.add_argument("--files", default="*.md", help="Glob pattern within docs-dir to translate (default: *.md)") + parser.add_argument("--force", action="store_true", help="Overwrite existing translations") + parser.add_argument("--max-chunk-lines", type=int, default=DEFAULT_MAX_CHUNK_LINES) + parser.add_argument("--max-chunk-chars", type=int, default=DEFAULT_MAX_CHUNK_CHARS) + parser.add_argument("--retries", type=int, default=DEFAULT_RETRIES) + parser.add_argument("--num-ctx", type=int, default=DEFAULT_NUM_CTX) + parser.add_argument("--num-predict", type=int, default=DEFAULT_NUM_PREDICT) + parser.add_argument("--temperature", type=float, default=DEFAULT_TEMPERATURE) + args = parser.parse_args() + + langs = _parse_langs(args.langs) + + client = OllamaClient( + url=args.ollama_url, + model=args.model, + num_ctx=args.num_ctx, + num_predict=args.num_predict, + temperature=args.temperature, + top_p=DEFAULT_TOP_P, + repeat_penalty=DEFAULT_REPEAT_PENALTY, + keep_alive=DEFAULT_KEEP_ALIVE, + ) + + docs_dir = args.docs_dir + patterns = [args.files] + + files: List[str] = [] + for pattern in patterns: + for path in glob.glob(os.path.join(docs_dir, pattern)): # Skip files that are already translated (contain e.g. .es.md) if any(f".{code}." in path for code in LANGUAGES.values()): continue files.append(path) + files = sorted(set(files)) if not files: - print("No source files found in docs/") + print(f"No source files found in {docs_dir}") return - print(f"Found {len(files)} files to translate in '{DOCS_DIR}'.") - print(f"Using Ollama model: {OLLAMA_MODEL}") + print(f"Found {len(files)} files to translate in '{docs_dir}'.") + print(f"Using Ollama model: {client.model}") + print(f"Chunking: <= {args.max_chunk_lines} lines, <= {args.max_chunk_chars} chars") print("-" * 40) for filepath in files: @@ -74,32 +827,43 @@ def main(): extension = path_obj.suffix print(f"Processing: {filepath}") - - with open(filepath, 'r', encoding='utf-8') as f: + with open(filepath, "r", encoding="utf-8") as f: content = f.read() if not content.strip(): print(" Skipping empty file.") continue - for lang_name, lang_code in LANGUAGES.items(): + for lang_name, lang_code in langs.items(): out_filename = f"{filename_without_ext}.{lang_code}{extension}" - out_filepath = os.path.join(DOCS_DIR, out_filename) - - # Skip if file already exists AND has content (handles empty corrupted files from timeouts) - if os.path.exists(out_filepath) and os.path.getsize(out_filepath) > 0: - print(f" [-] Skipping {lang_name} ({out_filename}) - already exists.") - continue + out_filepath = os.path.join(docs_dir, out_filename) + + if os.path.exists(out_filepath) and os.path.getsize(out_filepath) > 0 and not args.force: + with open(out_filepath, "r", encoding="utf-8") as existing_f: + existing = existing_f.read() + if not looks_incomplete(existing, content): + print(f" [-] Skipping {lang_name} ({out_filename}) - already exists.") + continue + print(f" [!] Existing {lang_name} looks incomplete; re-translating...") print(f" [+] Translating to {lang_name}...") - translated_content = translate_text(content, lang_name) - - if translated_content: - with open(out_filepath, 'w', encoding='utf-8') as out_f: - out_f.write(translated_content) + translated = translate_markdown_document( + client, + content=content, + target_language_name=lang_name, + target_language_code=lang_code, + max_chunk_lines=args.max_chunk_lines, + max_chunk_chars=args.max_chunk_chars, + retries=args.retries, + ) + + if translated: + with open(out_filepath, "w", encoding="utf-8") as out_f: + out_f.write(translated) print(f" Saved -> {out_filepath}") else: print(f" Failed to translate {filepath} to {lang_name}.") + if __name__ == "__main__": main() diff --git a/trustgraph-base/pyproject.toml b/trustgraph-base/pyproject.toml index 7d9f9219..08910a53 100644 --- a/trustgraph-base/pyproject.toml +++ b/trustgraph-base/pyproject.toml @@ -26,5 +26,8 @@ Homepage = "https://github.com/trustgraph-ai/trustgraph" [tool.setuptools.packages.find] include = ["trustgraph*"] +[tool.setuptools.package-data] +"trustgraph.i18n.packs" = ["*.json"] + [tool.setuptools.dynamic] version = {attr = "trustgraph.base_version.__version__"} \ No newline at end of file diff --git a/trustgraph-base/trustgraph/i18n/__init__.py b/trustgraph-base/trustgraph/i18n/__init__.py new file mode 100644 index 00000000..77674bf8 --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/__init__.py @@ -0,0 +1,153 @@ +"""Minimal i18n support for TrustGraph. + +This module intentionally stays lightweight: +- No runtime translation calls +- Translations are pre-generated and shipped as language packs + +Consumers (CLI/API/Workbench) select a language code (e.g. "es") and +use `Translator.t(key, **kwargs)` to format localized strings. +""" + +from __future__ import annotations + +import json +from dataclasses import dataclass +from functools import lru_cache +from typing import Any, Dict, Mapping, Optional + +import importlib.resources as importlib_resources + + +SUPPORTED_LANGUAGES: Mapping[str, str] = { + "en": "English", + "es": "Spanish", + "sw": "Swahili", + "pt": "Portuguese", + "tr": "Turkish", + "hi": "Hindi", + "he": "Hebrew", + "ar": "Arabic", + "zh-cn": "Chinese (simplified)", + "ru": "Russian", +} + +_LANGUAGE_ALIASES: Mapping[str, str] = { + "zh": "zh-cn", + "zh-hans": "zh-cn", + "zh-hans-cn": "zh-cn", + "zh-cn": "zh-cn", + "zh_cn": "zh-cn", +} + + +def normalize_language(value: Optional[str]) -> str: + """Normalize language inputs to our supported codes. + + Accepts: + - Simple codes: "es" + - Region tags: "es-ES", "en-US" + - Accept-Language style: "es-ES,es;q=0.9,en;q=0.8" + + Falls back to "en" when unknown. + """ + + if not value: + return "en" + + # Accept-Language: take first entry + token = value.split(",", 1)[0].strip() + if not token: + return "en" + + token = token.replace("_", "-").lower() + + # Exact alias mapping + if token in _LANGUAGE_ALIASES: + token = _LANGUAGE_ALIASES[token] + + # Collapse common regional tags + if token.startswith("en-"): + token = "en" + elif token.startswith("es-"): + token = "es" + elif token.startswith("pt-"): + token = "pt" + elif token.startswith("tr-"): + token = "tr" + elif token.startswith("hi-"): + token = "hi" + elif token.startswith("he-"): + token = "he" + elif token.startswith("ar-"): + token = "ar" + elif token.startswith("sw-"): + token = "sw" + elif token.startswith("ru-"): + token = "ru" + elif token.startswith("zh-"): + token = "zh-cn" + + # Otherwise use primary subtag + primary = token.split("-", 1)[0] + if primary in SUPPORTED_LANGUAGES: + return primary + + if token in SUPPORTED_LANGUAGES: + return token + + return "en" + + +@lru_cache(maxsize=32) +def get_language_pack(language: str) -> Dict[str, str]: + """Load the language pack for `language` from package resources.""" + + lang = normalize_language(language) + + try: + with importlib_resources.open_text( + "trustgraph.i18n.packs", f"{lang}.json", encoding="utf-8" + ) as f: + data = json.load(f) + except FileNotFoundError: + data = {} + + if not isinstance(data, dict): + return {} + + # Ensure values are strings + out: Dict[str, str] = {} + for k, v in data.items(): + if isinstance(k, str) and isinstance(v, str): + out[k] = v + return out + + +@dataclass(frozen=True) +class Translator: + language: str + + def t(self, key: str, **kwargs: Any) -> str: + """Translate `key` using the current language pack. + + Falls back to English pack, then the key itself. + Supports `.format(**kwargs)` placeholder substitution. + """ + + lang = normalize_language(self.language) + pack = get_language_pack(lang) + fallback = get_language_pack("en") + + template = pack.get(key) or fallback.get(key) or key + if not kwargs: + return template + + try: + return template.format(**kwargs) + except Exception: + # If formatting fails, return the untranslated template + return template + + +def get_translator(language: Optional[str]) -> Translator: + return Translator(language=normalize_language(language)) diff --git a/trustgraph-base/trustgraph/i18n/packs/__init__.py b/trustgraph-base/trustgraph/i18n/packs/__init__.py new file mode 100644 index 00000000..db8af56e --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/__init__.py @@ -0,0 +1 @@ +# Language packs live next to this module as JSON files. diff --git a/trustgraph-base/trustgraph/i18n/packs/ar.json b/trustgraph-base/trustgraph/i18n/packs/ar.json new file mode 100644 index 00000000..c910df29 --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/ar.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "التحقق من حالة نظام TrustGraph.", + "cli.verify_system_status.phase_1": "المرحلة الأولى: البنية التحتية.", + "cli.verify_system_status.phase_2": "المرحلة الثانية: الخدمات الأساسية.", + "cli.verify_system_status.phase_3": "المرحلة الثالثة: خدمات البيانات.", + "cli.verify_system_status.phase_4": "المرحلة الرابعة: واجهة المستخدم.", + "cli.verify_system_status.summary": "ملخص.", + "cli.verify_system_status.checking": "التحقق من {name}...", + "cli.verify_system_status.checking_attempt": "التحقق من {name}... (المحاولة {attempt}).", + "cli.verify_system_status.failed_timeout": "{name}: فشل (انتهت المهلة بعد {attempt} محاولة).", + "cli.verify_system_status.pulsar_not_responding": "Pulsar لا تستجيب - قد تفشل عمليات التحقق الأخرى.", + "cli.verify_system_status.checks_passed": "عمليات التحقق التي نجحت: {passed}/{total}.", + "cli.verify_system_status.checks_failed": "عمليات التحقق التي فشلت: {failed}/{total}.", + "cli.verify_system_status.total_time": "إجمالي الوقت: {elapsed}.", + "cli.verify_system_status.system_healthy": "النظام يعمل بشكل صحيح!", + "cli.verify_system_status.system_failing": "النظام لديه {failed} عملية تحقق فاشلة.", + "cli.verify_system_status.check_name.pulsar": "Pulsar.", + "cli.verify_system_status.check_name.api_gateway": "بوابة واجهة برمجة التطبيقات (API Gateway).", + "cli.verify_system_status.check_name.processors": "المعالجات (Processors).", + "cli.verify_system_status.check_name.flow_blueprints": "مخططات التدفق (Flow Blueprints).", + "cli.verify_system_status.check_name.flows": "التدفقات (Flows).", + "cli.verify_system_status.check_name.prompts": "المطالبات (Prompts).", + "cli.verify_system_status.check_name.library": "المكتبة (Library).", + "cli.verify_system_status.check_name.workbench_ui": "واجهة المستخدم الخاصة بـ Workbench.", + "cli.verify_system_status.pulsar.healthy": "Pulsar تعمل بشكل صحيح ({clusters} مجموعة).", + "cli.verify_system_status.pulsar.status": "Pulsar أرجعت الحالة {status_code}.", + "cli.verify_system_status.pulsar.timeout": "Pulsar: انتهاء المهلة.", + "cli.verify_system_status.pulsar.cannot_connect": "لا يمكن الاتصال بـ Pulsar.", + "cli.verify_system_status.pulsar.error": "Pulsar: خطأ: {error}.", + "cli.verify_system_status.api_gateway.responding": "بوابة واجهة برمجة التطبيقات (API Gateway) تستجيب.", + "cli.verify_system_status.api_gateway.status": "بوابة واجهة برمجة التطبيقات (API Gateway) أرجعت الحالة {status_code}.", + "cli.verify_system_status.api_gateway.timeout": "بوابة واجهة برمجة التطبيقات (API Gateway): انتهاء المهلة.", + "cli.verify_system_status.api_gateway.cannot_connect": "لا يمكن الاتصال بـ بوابة واجهة برمجة التطبيقات (API Gateway).", + "cli.verify_system_status.api_gateway.error": "بوابة واجهة برمجة التطبيقات (API Gateway): خطأ: {error}.", + "cli.verify_system_status.processors.found": "تم العثور على {count} معالج (≥ {min}).", + "cli.verify_system_status.processors.only": "فقط {count} معالج قيد التشغيل (مطلوب {min}).", + "cli.verify_system_status.processors.metrics_status": "المقاييس أرجعت الحالة {status_code}.", + "cli.verify_system_status.processors.error": "خطأ في فحص المعالج: {error}.", + "cli.verify_system_status.flow_blueprints.found": "تم العثور على {count} مخطط تدفق.", + "cli.verify_system_status.flow_blueprints.none": "لم يتم العثور على أي مخططات تدفق.", + "cli.verify_system_status.flow_blueprints.error": "خطأ في فحص مخططات التدفق: {error}.", + "cli.verify_system_status.flows.responding": "مدير التدفق يستجيب ({count} تدفق).", + "cli.verify_system_status.flows.error": "خطأ في فحص مدير التدفق: {error}.", + "cli.verify_system_status.prompts.found": "تم العثور على {count} مطالبة.", + "cli.verify_system_status.prompts.none": "لم يتم العثور على أي مطالبات.", + "cli.verify_system_status.prompts.error": "خطأ في فحص المطالبات: {error}.", + "cli.verify_system_status.library.responding": "المكتبة تستجيب ({count} مستند).", + "cli.verify_system_status.library.error": "خطأ في فحص المكتبة: {error}.", + "cli.verify_system_status.ui.responding": "واجهة المستخدم الخاصة بـ Workbench تستجيب.", + "cli.verify_system_status.ui.status": "واجهة المستخدم أرجعت الحالة {status_code}.", + "cli.verify_system_status.ui.timeout": "واجهة المستخدم: انتهاء المهلة.", + "cli.verify_system_status.ui.cannot_connect": "لا يمكن الاتصال بواجهة المستخدم.", + "cli.verify_system_status.ui.error": "واجهة المستخدم: خطأ: {error}." +} diff --git a/trustgraph-base/trustgraph/i18n/packs/en.json b/trustgraph-base/trustgraph/i18n/packs/en.json new file mode 100644 index 00000000..8438b7e7 --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/en.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "TrustGraph System Status Verification", + "cli.verify_system_status.phase_1": "Phase 1: Infrastructure", + "cli.verify_system_status.phase_2": "Phase 2: Core Services", + "cli.verify_system_status.phase_3": "Phase 3: Data Services", + "cli.verify_system_status.phase_4": "Phase 4: User Interface", + "cli.verify_system_status.summary": "Summary", + "cli.verify_system_status.checking": "Checking {name}...", + "cli.verify_system_status.checking_attempt": "Checking {name}... (attempt {attempt})", + "cli.verify_system_status.failed_timeout": "{name}: Failed (timeout after {attempt} attempts)", + "cli.verify_system_status.pulsar_not_responding": "Pulsar is not responding - other checks may fail", + "cli.verify_system_status.checks_passed": "Checks passed: {passed}/{total}", + "cli.verify_system_status.checks_failed": "Checks failed: {failed}/{total}", + "cli.verify_system_status.total_time": "Total time: {elapsed}", + "cli.verify_system_status.system_healthy": "System is healthy!", + "cli.verify_system_status.system_failing": "System has {failed} failing check(s)", + "cli.verify_system_status.check_name.pulsar": "Pulsar", + "cli.verify_system_status.check_name.api_gateway": "API Gateway", + "cli.verify_system_status.check_name.processors": "Processors", + "cli.verify_system_status.check_name.flow_blueprints": "Flow Blueprints", + "cli.verify_system_status.check_name.flows": "Flows", + "cli.verify_system_status.check_name.prompts": "Prompts", + "cli.verify_system_status.check_name.library": "Library", + "cli.verify_system_status.check_name.workbench_ui": "Workbench UI", + "cli.verify_system_status.pulsar.healthy": "Pulsar healthy ({clusters} cluster(s))", + "cli.verify_system_status.pulsar.status": "Pulsar returned status {status_code}", + "cli.verify_system_status.pulsar.timeout": "Pulsar connection timeout", + "cli.verify_system_status.pulsar.cannot_connect": "Cannot connect to Pulsar", + "cli.verify_system_status.pulsar.error": "Pulsar error: {error}", + "cli.verify_system_status.api_gateway.responding": "API Gateway is responding", + "cli.verify_system_status.api_gateway.status": "API Gateway returned status {status_code}", + "cli.verify_system_status.api_gateway.timeout": "API Gateway connection timeout", + "cli.verify_system_status.api_gateway.cannot_connect": "Cannot connect to API Gateway", + "cli.verify_system_status.api_gateway.error": "API Gateway error: {error}", + "cli.verify_system_status.processors.found": "Found {count} processors (≥ {min})", + "cli.verify_system_status.processors.only": "Only {count} processors running (need {min})", + "cli.verify_system_status.processors.metrics_status": "Metrics returned status {status_code}", + "cli.verify_system_status.processors.error": "Processor check error: {error}", + "cli.verify_system_status.flow_blueprints.found": "Found {count} flow blueprint(s)", + "cli.verify_system_status.flow_blueprints.none": "No flow blueprints found", + "cli.verify_system_status.flow_blueprints.error": "Flow blueprints check error: {error}", + "cli.verify_system_status.flows.responding": "Flow manager responding ({count} flow(s))", + "cli.verify_system_status.flows.error": "Flow manager check error: {error}", + "cli.verify_system_status.prompts.found": "Found {count} prompt(s)", + "cli.verify_system_status.prompts.none": "No prompts found", + "cli.verify_system_status.prompts.error": "Prompts check error: {error}", + "cli.verify_system_status.library.responding": "Library responding ({count} document(s))", + "cli.verify_system_status.library.error": "Library check error: {error}", + "cli.verify_system_status.ui.responding": "Workbench UI is responding", + "cli.verify_system_status.ui.status": "UI returned status {status_code}", + "cli.verify_system_status.ui.timeout": "UI connection timeout", + "cli.verify_system_status.ui.cannot_connect": "Cannot connect to UI", + "cli.verify_system_status.ui.error": "UI error: {error}" +} diff --git a/trustgraph-base/trustgraph/i18n/packs/es.json b/trustgraph-base/trustgraph/i18n/packs/es.json new file mode 100644 index 00000000..64b79cd6 --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/es.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "Verificación del estado del sistema TrustGraph", + "cli.verify_system_status.phase_1": "Fase 1: Infraestructura", + "cli.verify_system_status.phase_2": "Fase 2: Servicios principales", + "cli.verify_system_status.phase_3": "Fase 3: Servicios de datos", + "cli.verify_system_status.phase_4": "Fase 4: Interfaz de usuario", + "cli.verify_system_status.summary": "Resumen", + "cli.verify_system_status.checking": "Verificando {name}...", + "cli.verify_system_status.checking_attempt": "Verificando {name}... (intento {attempt})", + "cli.verify_system_status.failed_timeout": "{name}: Fallido (tiempo de espera después de {attempt} intentos)", + "cli.verify_system_status.pulsar_not_responding": "Pulsar no está respondiendo; otras verificaciones pueden fallar", + "cli.verify_system_status.checks_passed": "Verificaciones superadas: {passed}/{total}", + "cli.verify_system_status.checks_failed": "Verificaciones fallidas: {failed}/{total}", + "cli.verify_system_status.total_time": "Tiempo total: {elapsed}", + "cli.verify_system_status.system_healthy": "¡El sistema es saludable!", + "cli.verify_system_status.system_failing": "El sistema tiene {failed} verificación(es) fallida(s)", + "cli.verify_system_status.check_name.pulsar": "Pulsar", + "cli.verify_system_status.check_name.api_gateway": "API Gateway", + "cli.verify_system_status.check_name.processors": "Procesadores", + "cli.verify_system_status.check_name.flow_blueprints": "Plantillas de flujo", + "cli.verify_system_status.check_name.flows": "Flujos", + "cli.verify_system_status.check_name.prompts": "Indicaciones", + "cli.verify_system_status.check_name.library": "Biblioteca", + "cli.verify_system_status.check_name.workbench_ui": "Interfaz de usuario del entorno de trabajo", + "cli.verify_system_status.pulsar.healthy": "Pulsar saludable ({clusters} clúster(es))", + "cli.verify_system_status.pulsar.status": "Pulsar devolvió el estado {status_code}", + "cli.verify_system_status.pulsar.timeout": "Tiempo de espera de la conexión a Pulsar", + "cli.verify_system_status.pulsar.cannot_connect": "No se puede conectar a Pulsar", + "cli.verify_system_status.pulsar.error": "Error de Pulsar: {error}", + "cli.verify_system_status.api_gateway.responding": "API Gateway está respondiendo", + "cli.verify_system_status.api_gateway.status": "API Gateway devolvió el estado {status_code}", + "cli.verify_system_status.api_gateway.timeout": "Tiempo de espera de la conexión a API Gateway", + "cli.verify_system_status.api_gateway.cannot_connect": "No se puede conectar a API Gateway", + "cli.verify_system_status.api_gateway.error": "Error de API Gateway: {error}", + "cli.verify_system_status.processors.found": "Se encontraron {count} procesadores (≥ {min})", + "cli.verify_system_status.processors.only": "Solo {count} procesadores en ejecución (se necesitan {min})", + "cli.verify_system_status.processors.metrics_status": "Métricas devolvieron el estado {status_code}", + "cli.verify_system_status.processors.error": "Error de verificación del procesador: {error}", + "cli.verify_system_status.flow_blueprints.found": "Se encontraron {count} plantilla(s) de flujo", + "cli.verify_system_status.flow_blueprints.none": "No se encontraron plantillas de flujo", + "cli.verify_system_status.flow_blueprints.error": "Error de verificación de la plantilla de flujo: {error}", + "cli.verify_system_status.flows.responding": "El administrador de flujos está respondiendo ({count} flujo(s))", + "cli.verify_system_status.flows.error": "Error de verificación del administrador de flujos: {error}", + "cli.verify_system_status.prompts.found": "Se encontraron {count} indicación(es)", + "cli.verify_system_status.prompts.none": "No se encontraron indicaciones", + "cli.verify_system_status.prompts.error": "Error de verificación de la indicación: {error}", + "cli.verify_system_status.library.responding": "La biblioteca está respondiendo ({count} documento(s))", + "cli.verify_system_status.library.error": "Error de verificación de la biblioteca: {error}", + "cli.verify_system_status.ui.responding": "La interfaz de usuario del entorno de trabajo está respondiendo", + "cli.verify_system_status.ui.status": "La interfaz de usuario devolvió el estado {status_code}", + "cli.verify_system_status.ui.timeout": "Tiempo de espera de la conexión a la interfaz de usuario", + "cli.verify_system_status.ui.cannot_connect": "No se puede conectar a la interfaz de usuario", + "cli.verify_system_status.ui.error": "Error de la interfaz de usuario: {error}" +} diff --git a/trustgraph-base/trustgraph/i18n/packs/he.json b/trustgraph-base/trustgraph/i18n/packs/he.json new file mode 100644 index 00000000..9ad9ad90 --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/he.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "אימות סטטוס מערכת TrustGraph", + "cli.verify_system_status.phase_1": "שלב 1: תשתית", + "cli.verify_system_status.phase_2": "שלב 2: שירותים מרכזיים", + "cli.verify_system_status.phase_3": "שלב 3: שירותי נתונים", + "cli.verify_system_status.phase_4": "שלב 4: ממשק משתמש", + "cli.verify_system_status.summary": "סיכום", + "cli.verify_system_status.checking": "בדיקת {name}...", + "cli.verify_system_status.checking_attempt": "בדיקת {name}... (ניסיון {attempt})", + "cli.verify_system_status.failed_timeout": "{name}: נכשל (תפוגה לאחר {attempt} ניסיונות)", + "cli.verify_system_status.pulsar_not_responding": "Pulsar אינו מגיב - בדיקות אחרות עשויות להיכשל", + "cli.verify_system_status.checks_passed": "בדיקות שעברו: {passed}/{total}", + "cli.verify_system_status.checks_failed": "בדיקות שנכשלו: {failed}/{total}", + "cli.verify_system_status.total_time": "זמן כולל: {elapsed}", + "cli.verify_system_status.system_healthy": "המערכת תקינה!", + "cli.verify_system_status.system_failing": "למערכת יש {failed} בדיקה/ות שנכשלו", + "cli.verify_system_status.check_name.pulsar": "Pulsar", + "cli.verify_system_status.check_name.api_gateway": "API Gateway", + "cli.verify_system_status.check_name.processors": "מעבדים", + "cli.verify_system_status.check_name.flow_blueprints": "תבניות זרימה", + "cli.verify_system_status.check_name.flows": "זרימות", + "cli.verify_system_status.check_name.prompts": "הנחיות", + "cli.verify_system_status.check_name.library": "ספרייה", + "cli.verify_system_status.check_name.workbench_ui": "ממשק משתמש (Workbench UI)", + "cli.verify_system_status.pulsar.healthy": "Pulsar תקין ({clusters} אשכולות)", + "cli.verify_system_status.pulsar.status": "Pulsar החזיר סטטוס {status_code}", + "cli.verify_system_status.pulsar.timeout": "תפוגת זמן חיבור ל-Pulsar", + "cli.verify_system_status.pulsar.cannot_connect": "לא ניתן להתחבר ל-Pulsar", + "cli.verify_system_status.pulsar.error": "שגיאה ב-Pulsar: {error}", + "cli.verify_system_status.api_gateway.responding": "API Gateway מגיב", + "cli.verify_system_status.api_gateway.status": "API Gateway החזיר סטטוס {status_code}", + "cli.verify_system_status.api_gateway.timeout": "תפוגת זמן חיבור ל-API Gateway", + "cli.verify_system_status.api_gateway.cannot_connect": "לא ניתן להתחבר ל-API Gateway", + "cli.verify_system_status.api_gateway.error": "שגיאה ב-API Gateway: {error}", + "cli.verify_system_status.processors.found": "נמצאו {count} מעבדים (≥ {min})", + "cli.verify_system_status.processors.only": "פועלים רק {count} מעבדים (נדרשים {min})", + "cli.verify_system_status.processors.metrics_status": "Metrics החזירו סטטוס {status_code}", + "cli.verify_system_status.processors.error": "שגיאת בדיקת מעבד: {error}", + "cli.verify_system_status.flow_blueprints.found": "נמצאו {count} תבניות זרימה", + "cli.verify_system_status.flow_blueprints.none": "לא נמצאו תבניות זרימה", + "cli.verify_system_status.flow_blueprints.error": "שגיאת בדיקת תבניות זרימה: {error}", + "cli.verify_system_status.flows.responding": "מנהל הזרימה מגיב ({count} זרימות)", + "cli.verify_system_status.flows.error": "שגיאת בדיקת מנהל הזרימה: {error}", + "cli.verify_system_status.prompts.found": "נמצאו {count} הנחיות", + "cli.verify_system_status.prompts.none": "לא נמצאו הנחיות", + "cli.verify_system_status.prompts.error": "שגיאת בדיקת הנחיות: {error}", + "cli.verify_system_status.library.responding": "הספרייה מגיבה ({count} מסמכים)", + "cli.verify_system_status.library.error": "שגיאת בדיקת ספרייה: {error}", + "cli.verify_system_status.ui.responding": "ממשק המשתמש (Workbench UI) מגיב", + "cli.verify_system_status.ui.status": "ממשק המשתמש החזיר סטטוס {status_code}", + "cli.verify_system_status.ui.timeout": "תפוגת זמן חיבור לממשק המשתמש", + "cli.verify_system_status.ui.cannot_connect": "לא ניתן להתחבר לממשק המשתמש", + "cli.verify_system_status.ui.error": "שגיאה בממשק המשתמש: {error}" +} diff --git a/trustgraph-base/trustgraph/i18n/packs/hi.json b/trustgraph-base/trustgraph/i18n/packs/hi.json new file mode 100644 index 00000000..9783319b --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/hi.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "ट्रस्टग्राफ सिस्टम स्टेटस वेरिफिकेशन", + "cli.verify_system_status.phase_1": "चरण 1: इंफ्रास्ट्रक्चर", + "cli.verify_system_status.phase_2": "चरण 2: कोर सर्विसेज", + "cli.verify_system_status.phase_3": "चरण 3: डेटा सर्विसेज", + "cli.verify_system_status.phase_4": "चरण 4: यूजर इंटरफेस", + "cli.verify_system_status.summary": "सारांश", + "cli.verify_system_status.checking": "{name} की जाँच की जा रही है...", + "cli.verify_system_status.checking_attempt": "{name} की जाँच की जा रही है... (प्रयास {attempt})", + "cli.verify_system_status.failed_timeout": "{name}: विफल ({attempt} प्रयासों के बाद टाइमआउट)", + "cli.verify_system_status.pulsar_not_responding": "पल्सर प्रतिक्रिया नहीं दे रहा है - अन्य जाँचें विफल हो सकती हैं", + "cli.verify_system_status.checks_passed": "पास हुई जाँचें: {passed}/{total}", + "cli.verify_system_status.checks_failed": "विफल हुई जाँचें: {failed}/{total}", + "cli.verify_system_status.total_time": "कुल समय: {elapsed}", + "cli.verify_system_status.system_healthy": "सिस्टम स्वस्थ है!", + "cli.verify_system_status.system_failing": "सिस्टम में {failed} विफल जाँच(एँ) हैं", + "cli.verify_system_status.check_name.pulsar": "पल्सर", + "cli.verify_system_status.check_name.api_gateway": "एपीआई गेटवे", + "cli.verify_system_status.check_name.processors": "प्रोसेसर", + "cli.verify_system_status.check_name.flow_blueprints": "फ्लो ब्लूप्रिंट्स", + "cli.verify_system_status.check_name.flows": "फ्लोस", + "cli.verify_system_status.check_name.prompts": "प्रॉम्प्ट्स", + "cli.verify_system_status.check_name.library": "लाइब्रेरी", + "cli.verify_system_status.check_name.workbench_ui": "वर्कबेंच यूआई", + "cli.verify_system_status.pulsar.healthy": "पल्सर स्वस्थ ({clusters} क्लस्टर(्स))", + "cli.verify_system_status.pulsar.status": "पल्सर ने स्टेटस {status_code} लौटाया", + "cli.verify_system_status.pulsar.timeout": "पल्सर कनेक्शन टाइमआउट", + "cli.verify_system_status.pulsar.cannot_connect": "पल्सर से कनेक्ट नहीं किया जा सका", + "cli.verify_system_status.pulsar.error": "पल्सर त्रुटि: {error}", + "cli.verify_system_status.api_gateway.responding": "एपीआई गेटवे प्रतिक्रिया दे रहा है", + "cli.verify_system_status.api_gateway.status": "एपीआई गेटवे ने स्टेटस {status_code} लौटाया", + "cli.verify_system_status.api_gateway.timeout": "एपीआई गेटवे कनेक्शन टाइमआउट", + "cli.verify_system_status.api_gateway.cannot_connect": "एपीआई गेटवे से कनेक्ट नहीं किया जा सका", + "cli.verify_system_status.api_gateway.error": "एपीआई गेटवे त्रुटि: {error}", + "cli.verify_system_status.processors.found": "{count} प्रोसेसर पाए गए (≥ {min})", + "cli.verify_system_status.processors.only": "केवल {count} प्रोसेसर चल रहे हैं (आवश्यक {min})", + "cli.verify_system_status.processors.metrics_status": "मेट्रिक्स ने स्टेटस {status_code} लौटाया", + "cli.verify_system_status.processors.error": "प्रोसेसर जाँच त्रुटि: {error}", + "cli.verify_system_status.flow_blueprints.found": "{count} फ्लो ब्लूप्रिंट पाए गए", + "cli.verify_system_status.flow_blueprints.none": "कोई फ्लो ब्लूप्रिंट नहीं मिला", + "cli.verify_system_status.flow_blueprints.error": "फ्लो ब्लूप्रिंट जाँच त्रुटि: {error}", + "cli.verify_system_status.flows.responding": "फ्लो मैनेजर प्रतिक्रिया दे रहा है ({count} फ्लो(्स))", + "cli.verify_system_status.flows.error": "फ्लो मैनेजर जाँच त्रुटि: {error}", + "cli.verify_system_status.prompts.found": "{count} प्रॉम्प्ट पाए गए", + "cli.verify_system_status.prompts.none": "कोई प्रॉम्प्ट नहीं मिला", + "cli.verify_system_status.prompts.error": "प्रॉम्प्ट जाँच त्रुटि: {error}", + "cli.verify_system_status.library.responding": "लाइब्रेरी प्रतिक्रिया दे रही है ({count} दस्तावेज़(्स))", + "cli.verify_system_status.library.error": "लाइब्रेरी जाँच त्रुटि: {error}", + "cli.verify_system_status.ui.responding": "वर्कबेंच यूआई प्रतिक्रिया दे रहा है", + "cli.verify_system_status.ui.status": "यूआई ने स्टेटस {status_code} लौटाया", + "cli.verify_system_status.ui.timeout": "यूआई कनेक्शन टाइमआउट", + "cli.verify_system_status.ui.cannot_connect": "यूआई से कनेक्ट नहीं किया जा सका", + "cli.verify_system_status.ui.error": "यूआई त्रुटि: {error}" +} diff --git a/trustgraph-base/trustgraph/i18n/packs/pt.json b/trustgraph-base/trustgraph/i18n/packs/pt.json new file mode 100644 index 00000000..7238f086 --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/pt.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "Verificação do Status do Sistema TrustGraph", + "cli.verify_system_status.phase_1": "Fase 1: Infraestrutura", + "cli.verify_system_status.phase_2": "Fase 2: Serviços Essenciais", + "cli.verify_system_status.phase_3": "Fase 3: Serviços de Dados", + "cli.verify_system_status.phase_4": "Fase 4: Interface do Usuário", + "cli.verify_system_status.summary": "Resumo", + "cli.verify_system_status.checking": "Verificando {name}...", + "cli.verify_system_status.checking_attempt": "Verificando {name}... (tentativa {attempt})", + "cli.verify_system_status.failed_timeout": "{name}: Falha (tempo limite após {attempt} tentativas)", + "cli.verify_system_status.pulsar_not_responding": "O Pulsar não está respondendo - outras verificações podem falhar", + "cli.verify_system_status.checks_passed": "Verificações aprovadas: {passed}/{total}", + "cli.verify_system_status.checks_failed": "Verificações falhadas: {failed}/{total}", + "cli.verify_system_status.total_time": "Tempo total: {elapsed}", + "cli.verify_system_status.system_healthy": "O sistema está saudável!", + "cli.verify_system_status.system_failing": "O sistema possui {failed} verificação(ões) com falha", + "cli.verify_system_status.check_name.pulsar": "Pulsar", + "cli.verify_system_status.check_name.api_gateway": "API Gateway", + "cli.verify_system_status.check_name.processors": "Processadores", + "cli.verify_system_status.check_name.flow_blueprints": "Flow Blueprints", + "cli.verify_system_status.check_name.flows": "Flows", + "cli.verify_system_status.check_name.prompts": "Prompts", + "cli.verify_system_status.check_name.library": "Biblioteca", + "cli.verify_system_status.check_name.workbench_ui": "Workbench UI", + "cli.verify_system_status.pulsar.healthy": "Pulsar saudável ({clusters} cluster(s))", + "cli.verify_system_status.pulsar.status": "O Pulsar retornou o status {status_code}", + "cli.verify_system_status.pulsar.timeout": "Tempo limite de conexão do Pulsar", + "cli.verify_system_status.pulsar.cannot_connect": "Não foi possível conectar ao Pulsar", + "cli.verify_system_status.pulsar.error": "Erro do Pulsar: {error}", + "cli.verify_system_status.api_gateway.responding": "O API Gateway está respondendo", + "cli.verify_system_status.api_gateway.status": "O API Gateway retornou o status {status_code}", + "cli.verify_system_status.api_gateway.timeout": "Tempo limite de conexão do API Gateway", + "cli.verify_system_status.api_gateway.cannot_connect": "Não foi possível conectar ao API Gateway", + "cli.verify_system_status.api_gateway.error": "Erro do API Gateway: {error}", + "cli.verify_system_status.processors.found": "Encontrados {count} processadores (≥ {min})", + "cli.verify_system_status.processors.only": "Apenas {count} processadores em execução (necessários {min})", + "cli.verify_system_status.processors.metrics_status": "As métricas retornaram o status {status_code}", + "cli.verify_system_status.processors.error": "Erro de verificação do processador: {error}", + "cli.verify_system_status.flow_blueprints.found": "Encontrados {count} flow blueprint(s)", + "cli.verify_system_status.flow_blueprints.none": "Nenhum flow blueprint encontrado", + "cli.verify_system_status.flow_blueprints.error": "Erro de verificação do flow blueprint: {error}", + "cli.verify_system_status.flows.responding": "O gerenciador de fluxo está respondendo ({count} flow(s))", + "cli.verify_system_status.flows.error": "Erro de verificação do gerenciador de fluxo: {error}", + "cli.verify_system_status.prompts.found": "Encontrados {count} prompt(s)", + "cli.verify_system_status.prompts.none": "Nenhum prompt encontrado", + "cli.verify_system_status.prompts.error": "Erro de verificação do prompt: {error}", + "cli.verify_system_status.library.responding": "A biblioteca está respondendo ({count} document(s))", + "cli.verify_system_status.library.error": "Erro de verificação da biblioteca: {error}", + "cli.verify_system_status.ui.responding": "O Workbench UI está respondendo", + "cli.verify_system_status.ui.status": "A UI retornou o status {status_code}", + "cli.verify_system_status.ui.timeout": "Tempo limite de conexão da UI", + "cli.verify_system_status.ui.cannot_connect": "Não foi possível conectar à UI", + "cli.verify_system_status.ui.error": "Erro da UI: {error}" +} diff --git a/trustgraph-base/trustgraph/i18n/packs/ru.json b/trustgraph-base/trustgraph/i18n/packs/ru.json new file mode 100644 index 00000000..0e8420c2 --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/ru.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "Проверка состояния системы TrustGraph", + "cli.verify_system_status.phase_1": "Фаза 1: Инфраструктура", + "cli.verify_system_status.phase_2": "Фаза 2: Основные сервисы", + "cli.verify_system_status.phase_3": "Фаза 3: Сервисы данных", + "cli.verify_system_status.phase_4": "Фаза 4: Пользовательский интерфейс", + "cli.verify_system_status.summary": "Краткое описание", + "cli.verify_system_status.checking": "Проверка {name}...", + "cli.verify_system_status.checking_attempt": "Проверка {name}... (попытка {attempt})", + "cli.verify_system_status.failed_timeout": "{name}: Не удалось (тайм-аут после {attempt} попыток)", + "cli.verify_system_status.pulsar_not_responding": "Pulsar не отвечает - другие проверки могут не пройти", + "cli.verify_system_status.checks_passed": "Проверено: {passed}/{total}", + "cli.verify_system_status.checks_failed": "Не удалось: {failed}/{total}", + "cli.verify_system_status.total_time": "Общее время: {elapsed}", + "cli.verify_system_status.system_healthy": "Система в рабочем состоянии!", + "cli.verify_system_status.system_failing": "В системе {failed} неисправностей.", + "cli.verify_system_status.check_name.pulsar": "Pulsar", + "cli.verify_system_status.check_name.api_gateway": "API Gateway", + "cli.verify_system_status.check_name.processors": "Процессоры", + "cli.verify_system_status.check_name.flow_blueprints": "Шаблоны потоков", + "cli.verify_system_status.check_name.flows": "Потоки", + "cli.verify_system_status.check_name.prompts": "Подсказки", + "cli.verify_system_status.check_name.library": "Библиотека", + "cli.verify_system_status.check_name.workbench_ui": "Пользовательский интерфейс Workbench", + "cli.verify_system_status.pulsar.healthy": "Pulsar работает ({clusters} кластер(ов))", + "cli.verify_system_status.pulsar.status": "Pulsar вернул статус {status_code}", + "cli.verify_system_status.pulsar.timeout": "Время ожидания соединения с Pulsar истекло", + "cli.verify_system_status.pulsar.cannot_connect": "Не удалось подключиться к Pulsar", + "cli.verify_system_status.pulsar.error": "Ошибка Pulsar: {error}", + "cli.verify_system_status.api_gateway.responding": "API Gateway отвечает", + "cli.verify_system_status.api_gateway.status": "API Gateway вернул статус {status_code}", + "cli.verify_system_status.api_gateway.timeout": "Время ожидания соединения с API Gateway истекло", + "cli.verify_system_status.api_gateway.cannot_connect": "Не удалось подключиться к API Gateway", + "cli.verify_system_status.api_gateway.error": "Ошибка API Gateway: {error}", + "cli.verify_system_status.processors.found": "Обнаружено {count} процессоров (≥ {min})", + "cli.verify_system_status.processors.only": "Работает только {count} процессоров (требуется {min})", + "cli.verify_system_status.processors.metrics_status": "Метрики вернули статус {status_code}", + "cli.verify_system_status.processors.error": "Ошибка проверки процессора: {error}", + "cli.verify_system_status.flow_blueprints.found": "Обнаружено {count} шаблонов потоков", + "cli.verify_system_status.flow_blueprints.none": "Шаблоны потоков не найдены", + "cli.verify_system_status.flow_blueprints.error": "Ошибка проверки шаблонов потоков: {error}", + "cli.verify_system_status.flows.responding": "Менеджер потоков отвечает ({count} поток(ов))", + "cli.verify_system_status.flows.error": "Ошибка проверки менеджера потоков: {error}", + "cli.verify_system_status.prompts.found": "Обнаружено {count} подсказок", + "cli.verify_system_status.prompts.none": "Подсказки не найдены", + "cli.verify_system_status.prompts.error": "Ошибка проверки подсказок: {error}", + "cli.verify_system_status.library.responding": "Библиотека отвечает ({count} документ(ов))", + "cli.verify_system_status.library.error": "Ошибка проверки библиотеки: {error}", + "cli.verify_system_status.ui.responding": "Пользовательский интерфейс Workbench отвечает", + "cli.verify_system_status.ui.status": "Пользовательский интерфейс вернул статус {status_code}", + "cli.verify_system_status.ui.timeout": "Время ожидания соединения с пользовательским интерфейсом истекло", + "cli.verify_system_status.ui.cannot_connect": "Не удалось подключиться к пользовательскому интерфейсу", + "cli.verify_system_status.ui.error": "Ошибка пользовательского интерфейса: {error}" +} diff --git a/trustgraph-base/trustgraph/i18n/packs/sw.json b/trustgraph-base/trustgraph/i18n/packs/sw.json new file mode 100644 index 00000000..3aa8288a --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/sw.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "Uthibitisho wa Hali ya Mfumo wa TrustGraph", + "cli.verify_system_status.phase_1": "Awamu ya 1: Miundombinu", + "cli.verify_system_status.phase_2": "Awamu ya 2: Huduma za Msingi", + "cli.verify_system_status.phase_3": "Awamu ya 3: Huduma za Data", + "cli.verify_system_status.phase_4": "Awamu ya 4: Kiolesura cha Mtumiaji", + "cli.verify_system_status.summary": "Muhtasari", + "cli.verify_system_status.checking": "Kuchunguza {name}...", + "cli.verify_system_status.checking_attempt": "Kuchunguza {name}... (jaribio la {attempt})", + "cli.verify_system_status.failed_timeout": "{name}: Imeshindwa (iliyepuka baada ya majaribio {attempt})", + "cli.verify_system_status.pulsar_not_responding": "Pulsar haijibu - vipimo vingine vinaweza kushindwa", + "cli.verify_system_status.checks_passed": "Vipimo vilivyofaulu: {passed}/{total}", + "cli.verify_system_status.checks_failed": "Vipimo vilivyoshindwa: {failed}/{total}", + "cli.verify_system_status.total_time": "Muda jumla: {elapsed}", + "cli.verify_system_status.system_healthy": "Mfumo una afya!", + "cli.verify_system_status.system_failing": "Mfumo una {failed} kipimo(s) kilicho(s) kifeli(s)", + "cli.verify_system_status.check_name.pulsar": "Pulsar", + "cli.verify_system_status.check_name.api_gateway": "Milango ya API", + "cli.verify_system_status.check_name.processors": "Wasindikaji", + "cli.verify_system_status.check_name.flow_blueprints": "Mipango ya Mtiririko", + "cli.verify_system_status.check_name.flows": "Mitiririko", + "cli.verify_system_status.check_name.prompts": "Maagizo", + "cli.verify_system_status.check_name.library": "Maktaba", + "cli.verify_system_status.check_name.workbench_ui": "Kiolesura cha Kifaa cha Kazi", + "cli.verify_system_status.pulsar.healthy": "Pulsar ina afya (vikundi {clusters})", + "cli.verify_system_status.pulsar.status": "Pulsar ilirudisha hali {status_code}", + "cli.verify_system_status.pulsar.timeout": "Muda wa kuunganisha na Pulsar umepita", + "cli.verify_system_status.pulsar.cannot_connect": "Haiwezekani kuunganisha na Pulsar", + "cli.verify_system_status.pulsar.error": "Kosa la Pulsar: {error}", + "cli.verify_system_status.api_gateway.responding": "Milango ya API inajibu", + "cli.verify_system_status.api_gateway.status": "Milango ya API ilirudisha hali {status_code}", + "cli.verify_system_status.api_gateway.timeout": "Muda wa kuunganisha na Milango ya API umepita", + "cli.verify_system_status.api_gateway.cannot_connect": "Haiwezekani kuunganisha na Milango ya API", + "cli.verify_system_status.api_gateway.error": "Kosa la Milango ya API: {error}", + "cli.verify_system_status.processors.found": "Imebainika wasindikaji {count} (≥ {min})", + "cli.verify_system_status.processors.only": "Tu wasindikaji {count} wanaendesha (wanahitaji {min})", + "cli.verify_system_status.processors.metrics_status": "Vipimo vilirudisha hali {status_code}", + "cli.verify_system_status.processors.error": "Kosa la ukaguzi wa wasindikaji: {error}", + "cli.verify_system_status.flow_blueprints.found": "Imebainika mipango ya mtiririko {count}", + "cli.verify_system_status.flow_blueprints.none": "Hakuna mipango ya mtiririko iliyobainika", + "cli.verify_system_status.flow_blueprints.error": "Kosa la ukaguzi wa mipango ya mtiririko: {error}", + "cli.verify_system_status.flows.responding": "Kidhibiti cha mtiririko kinajibu (mitiririko {count})", + "cli.verify_system_status.flows.error": "Kosa la ukaguzi wa kidhibiti cha mtiririko: {error}", + "cli.verify_system_status.prompts.found": "Imebainika maagizo {count}", + "cli.verify_system_status.prompts.none": "Hakuna maagizo yaliyobainika", + "cli.verify_system_status.prompts.error": "Kosa la ukaguzi wa maagizo: {error}", + "cli.verify_system_status.library.responding": "Maktaba inajibu (nyaraka {count})", + "cli.verify_system_status.library.error": "Kosa la ukaguzi wa maktaba: {error}", + "cli.verify_system_status.ui.responding": "Kiolesura cha Kifaa cha Kazi kinajibu", + "cli.verify_system_status.ui.status": "Kiolesura kilirudisha hali {status_code}", + "cli.verify_system_status.ui.timeout": "Muda wa kuunganisha na kiolesura umepita", + "cli.verify_system_status.ui.cannot_connect": "Haiwezekani kuunganisha na kiolesura", + "cli.verify_system_status.ui.error": "Kosa la kiolesura: {error}" +} diff --git a/trustgraph-base/trustgraph/i18n/packs/tr.json b/trustgraph-base/trustgraph/i18n/packs/tr.json new file mode 100644 index 00000000..0a210043 --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/tr.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "TrustGraph Sistem Durumu Doğrulama", + "cli.verify_system_status.phase_1": "Aşama 1: Altyapı", + "cli.verify_system_status.phase_2": "Aşama 2: Temel Hizmetler", + "cli.verify_system_status.phase_3": "Aşama 3: Veri Hizmetleri", + "cli.verify_system_status.phase_4": "Aşama 4: Kullanıcı Arayüzü", + "cli.verify_system_status.summary": "Özet", + "cli.verify_system_status.checking": "{name}'ı kontrol ediliyor...", + "cli.verify_system_status.checking_attempt": "{name}'ı kontrol ediliyor... ({attempt} deneme)", + "cli.verify_system_status.failed_timeout": "{name}: Başarısız ({attempt} denemeden sonra zaman aşımı)", + "cli.verify_system_status.pulsar_not_responding": "Pulsar yanıt vermiyor - diğer kontroller başarısız olabilir", + "cli.verify_system_status.checks_passed": "Başarılı kontroller: {passed}/{total}", + "cli.verify_system_status.checks_failed": "Başarısız kontroller: {failed}/{total}", + "cli.verify_system_status.total_time": "Toplam süre: {elapsed}", + "cli.verify_system_status.system_healthy": "Sistem sağlıklı!", + "cli.verify_system_status.system_failing": "Sistemde {failed} adet başarısız kontrol var", + "cli.verify_system_status.check_name.pulsar": "Pulsar", + "cli.verify_system_status.check_name.api_gateway": "API Ağ Geçidi", + "cli.verify_system_status.check_name.processors": "İşlemciler", + "cli.verify_system_status.check_name.flow_blueprints": "Akış Şemaları", + "cli.verify_system_status.check_name.flows": "Akışlar", + "cli.verify_system_status.check_name.prompts": "İpuçları", + "cli.verify_system_status.check_name.library": "Kütüphane", + "cli.verify_system_status.check_name.workbench_ui": "Çalışma Alanı Arayüzü", + "cli.verify_system_status.pulsar.healthy": "Pulsar sağlıklı ({clusters} küme)", + "cli.verify_system_status.pulsar.status": "Pulsar, {status_code} durumunu döndürdü", + "cli.verify_system_status.pulsar.timeout": "Pulsar bağlantı zaman aşımı", + "cli.verify_system_status.pulsar.cannot_connect": "Pulsar'a bağlanılamıyor", + "cli.verify_system_status.pulsar.error": "Pulsar hatası: {error}", + "cli.verify_system_status.api_gateway.responding": "API Ağ Geçidi yanıt veriyor", + "cli.verify_system_status.api_gateway.status": "API Ağ Geçidi, {status_code} durumunu döndürdü", + "cli.verify_system_status.api_gateway.timeout": "API Ağ Geçidi bağlantı zaman aşımı", + "cli.verify_system_status.api_gateway.cannot_connect": "API Ağ Geçidi'ne bağlanılamıyor", + "cli.verify_system_status.api_gateway.error": "API Ağ Geçidi hatası: {error}", + "cli.verify_system_status.processors.found": "{count} adet işlemci bulundu (≥ {min})", + "cli.verify_system_status.processors.only": "Sadece {count} adet işlemci çalışıyor (gerekli {min})", + "cli.verify_system_status.processors.metrics_status": "Ölçümler, {status_code} durumunu döndürdü", + "cli.verify_system_status.processors.error": "İşlemci kontrol hatası: {error}", + "cli.verify_system_status.flow_blueprints.found": "{count} adet akış şeması bulundu", + "cli.verify_system_status.flow_blueprints.none": "Akış şeması bulunamadı", + "cli.verify_system_status.flow_blueprints.error": "Akış şeması kontrol hatası: {error}", + "cli.verify_system_status.flows.responding": "Akış yöneticisi yanıt veriyor ({count} akış)", + "cli.verify_system_status.flows.error": "Akış yöneticisi kontrol hatası: {error}", + "cli.verify_system_status.prompts.found": "{count} adet ipucu bulundu", + "cli.verify_system_status.prompts.none": "İpucu bulunamadı", + "cli.verify_system_status.prompts.error": "İpuçları kontrol hatası: {error}", + "cli.verify_system_status.library.responding": "Kütüphane yanıt veriyor ({count} belge)", + "cli.verify_system_status.library.error": "Kütüphane kontrol hatası: {error}", + "cli.verify_system_status.ui.responding": "Çalışma alanı Arayüzü yanıt veriyor", + "cli.verify_system_status.ui.status": "Arayüz, {status_code} durumunu döndürdü", + "cli.verify_system_status.ui.timeout": "Arayüz bağlantı zaman aşımı", + "cli.verify_system_status.ui.cannot_connect": "Arayüze bağlanılamıyor", + "cli.verify_system_status.ui.error": "Arayüz hatası: {error}" +} diff --git a/trustgraph-base/trustgraph/i18n/packs/zh-cn.json b/trustgraph-base/trustgraph/i18n/packs/zh-cn.json new file mode 100644 index 00000000..9084b367 --- /dev/null +++ b/trustgraph-base/trustgraph/i18n/packs/zh-cn.json @@ -0,0 +1,54 @@ +{ + "cli.verify_system_status.title": "TrustGraph 系统状态验证", + "cli.verify_system_status.phase_1": "第一阶段:基础设施", + "cli.verify_system_status.phase_2": "第二阶段:核心服务", + "cli.verify_system_status.phase_3": "第三阶段:数据服务", + "cli.verify_system_status.phase_4": "第四阶段:用户界面", + "cli.verify_system_status.summary": "总结", + "cli.verify_system_status.checking": "正在检查 {name}...", + "cli.verify_system_status.checking_attempt": "正在检查 {name}... (第 {attempt} 次尝试)", + "cli.verify_system_status.failed_timeout": "{name}: 失败 (在 {attempt} 次尝试后超时)", + "cli.verify_system_status.pulsar_not_responding": "Pulsar 未响应 - 其他检查可能失败", + "cli.verify_system_status.checks_passed": "通过检查: {passed}/{total}", + "cli.verify_system_status.checks_failed": "失败检查: {failed}/{total}", + "cli.verify_system_status.total_time": "总时间: {elapsed}", + "cli.verify_system_status.system_healthy": "系统状态良好!", + "cli.verify_system_status.system_failing": "系统有 {failed} 个失败的检查", + "cli.verify_system_status.check_name.pulsar": "Pulsar", + "cli.verify_system_status.check_name.api_gateway": "API 网关", + "cli.verify_system_status.check_name.processors": "处理程序", + "cli.verify_system_status.check_name.flow_blueprints": "流蓝图", + "cli.verify_system_status.check_name.flows": "流", + "cli.verify_system_status.check_name.prompts": "提示", + "cli.verify_system_status.check_name.library": "库", + "cli.verify_system_status.check_name.workbench_ui": "Workbench UI", + "cli.verify_system_status.pulsar.healthy": "Pulsar 状态良好 ({clusters} 个集群)", + "cli.verify_system_status.pulsar.status": "Pulsar 返回状态 {status_code}", + "cli.verify_system_status.pulsar.timeout": "Pulsar 连接超时", + "cli.verify_system_status.pulsar.cannot_connect": "无法连接到 Pulsar", + "cli.verify_system_status.pulsar.error": "Pulsar 错误: {error}", + "cli.verify_system_status.api_gateway.responding": "API 网关正在响应", + "cli.verify_system_status.api_gateway.status": "API 网关返回状态 {status_code}", + "cli.verify_system_status.api_gateway.timeout": "API 网关连接超时", + "cli.verify_system_status.api_gateway.cannot_connect": "无法连接到 API 网关", + "cli.verify_system_status.api_gateway.error": "API 网关错误: {error}", + "cli.verify_system_status.processors.found": "发现 {count} 个处理程序 (≥ {min})", + "cli.verify_system_status.processors.only": "只有 {count} 个处理程序正在运行 (需要 {min} 个)", + "cli.verify_system_status.processors.metrics_status": "Metrics 返回状态 {status_code}", + "cli.verify_system_status.processors.error": "处理程序检查错误: {error}", + "cli.verify_system_status.flow_blueprints.found": "发现 {count} 个流蓝图", + "cli.verify_system_status.flow_blueprints.none": "未发现任何流蓝图", + "cli.verify_system_status.flow_blueprints.error": "流蓝图检查错误: {error}", + "cli.verify_system_status.flows.responding": "流管理器正在响应 ({count} 个流)", + "cli.verify_system_status.flows.error": "流管理器检查错误: {error}", + "cli.verify_system_status.prompts.found": "发现 {count} 个提示", + "cli.verify_system_status.prompts.none": "未发现任何提示", + "cli.verify_system_status.prompts.error": "提示检查错误: {error}", + "cli.verify_system_status.library.responding": "库正在响应 ({count} 个文档)", + "cli.verify_system_status.library.error": "库检查错误: {error}", + "cli.verify_system_status.ui.responding": "Workbench UI 正在响应", + "cli.verify_system_status.ui.status": "UI 返回状态 {status_code}", + "cli.verify_system_status.ui.timeout": "UI 连接超时", + "cli.verify_system_status.ui.cannot_connect": "无法连接到 UI", + "cli.verify_system_status.ui.error": "UI 错误: {error}" +} diff --git a/trustgraph-cli/trustgraph/cli/verify_system_status.py b/trustgraph-cli/trustgraph/cli/verify_system_status.py index 5fea1bb0..1b3ec004 100644 --- a/trustgraph-cli/trustgraph/cli/verify_system_status.py +++ b/trustgraph-cli/trustgraph/cli/verify_system_status.py @@ -19,6 +19,7 @@ from typing import Tuple, Optional # Import existing CLI functions to reuse logic from trustgraph.api import Api +from trustgraph.i18n import get_translator default_pulsar_url = "http://localhost:8080" default_api_url = os.getenv("TRUSTGRAPH_URL", "http://localhost:8088/") @@ -34,12 +35,14 @@ class HealthChecker: global_timeout: int = 120, check_timeout: int = 10, retry_delay: int = 3, - verbose: bool = False + verbose: bool = False, + translator=None, ): self.global_timeout = global_timeout self.check_timeout = check_timeout self.retry_delay = retry_delay self.verbose = verbose + self.tr = translator self.start_time = time.time() self.checks_passed = 0 self.checks_failed = 0 @@ -98,9 +101,15 @@ class HealthChecker: attempt += 1 if attempt > 1: - self.log(f"Checking {name}... (attempt {attempt})", "progress") + if self.tr: + self.log(self.tr.t("cli.verify_system_status.checking_attempt", name=name, attempt=attempt), "progress") + else: + self.log(f"Checking {name}... (attempt {attempt})", "progress") else: - self.log(f"Checking {name}...", "progress") + if self.tr: + self.log(self.tr.t("cli.verify_system_status.checking", name=name), "progress") + else: + self.log(f"Checking {name}...", "progress") try: # Run the check with timeout @@ -124,29 +133,32 @@ class HealthChecker: time.sleep(self.retry_delay) # Check failed - self.log(f"{name}: Failed (timeout after {attempt} attempts)", "error") + if self.tr: + self.log(self.tr.t("cli.verify_system_status.failed_timeout", name=name, attempt=attempt), "error") + else: + self.log(f"{name}: Failed (timeout after {attempt} attempts)", "error") self.checks_failed += 1 return False -def check_pulsar(url: str, timeout: int) -> Tuple[bool, str]: +def check_pulsar(url: str, timeout: int, tr) -> Tuple[bool, str]: """Check if Pulsar admin API is responding.""" try: resp = requests.get(f"{url}/admin/v2/clusters", timeout=timeout) if resp.status_code == 200: clusters = resp.json() - return True, f"Pulsar healthy ({len(clusters)} cluster(s))" + return True, tr.t("cli.verify_system_status.pulsar.healthy", clusters=len(clusters)) else: - return False, f"Pulsar returned status {resp.status_code}" + return False, tr.t("cli.verify_system_status.pulsar.status", status_code=resp.status_code) except requests.exceptions.Timeout: - return False, "Pulsar connection timeout" + return False, tr.t("cli.verify_system_status.pulsar.timeout") except requests.exceptions.ConnectionError: - return False, "Cannot connect to Pulsar" + return False, tr.t("cli.verify_system_status.pulsar.cannot_connect") except Exception as e: - return False, f"Pulsar error: {e}" + return False, tr.t("cli.verify_system_status.pulsar.error", error=str(e)) -def check_api_gateway(url: str, timeout: int, token: Optional[str] = None) -> Tuple[bool, str]: +def check_api_gateway(url: str, timeout: int, tr, token: Optional[str] = None) -> Tuple[bool, str]: """Check if API Gateway is responding.""" try: # Try to hit the base URL @@ -159,18 +171,18 @@ def check_api_gateway(url: str, timeout: int, token: Optional[str] = None) -> Tu resp = requests.get(url, headers=headers, timeout=timeout) if resp.status_code in [200, 404]: # 404 is OK, means gateway is up - return True, "API Gateway is responding" + return True, tr.t("cli.verify_system_status.api_gateway.responding") else: - return False, f"API Gateway returned status {resp.status_code}" + return False, tr.t("cli.verify_system_status.api_gateway.status", status_code=resp.status_code) except requests.exceptions.Timeout: - return False, "API Gateway connection timeout" + return False, tr.t("cli.verify_system_status.api_gateway.timeout") except requests.exceptions.ConnectionError: - return False, "Cannot connect to API Gateway" + return False, tr.t("cli.verify_system_status.api_gateway.cannot_connect") except Exception as e: - return False, f"API Gateway error: {e}" + return False, tr.t("cli.verify_system_status.api_gateway.error", error=str(e)) -def check_processors(url: str, min_processors: int, timeout: int, token: Optional[str] = None) -> Tuple[bool, str]: +def check_processors(url: str, min_processors: int, timeout: int, tr, token: Optional[str] = None) -> Tuple[bool, str]: """Check if processors are running via metrics endpoint.""" try: # Construct metrics URL from API URL @@ -188,17 +200,17 @@ def check_processors(url: str, min_processors: int, timeout: int, token: Optiona processor_count = len(data.get("data", {}).get("result", [])) if processor_count >= min_processors: - return True, f"Found {processor_count} processors (≥ {min_processors})" + return True, tr.t("cli.verify_system_status.processors.found", count=processor_count, min=min_processors) else: - return False, f"Only {processor_count} processors running (need {min_processors})" + return False, tr.t("cli.verify_system_status.processors.only", count=processor_count, min=min_processors) else: - return False, f"Metrics returned status {resp.status_code}" + return False, tr.t("cli.verify_system_status.processors.metrics_status", status_code=resp.status_code) except Exception as e: - return False, f"Processor check error: {e}" + return False, tr.t("cli.verify_system_status.processors.error", error=str(e)) -def check_flow_blueprints(url: str, timeout: int, token: Optional[str] = None) -> Tuple[bool, str]: +def check_flow_blueprints(url: str, timeout: int, tr, token: Optional[str] = None) -> Tuple[bool, str]: """Check if flow blueprints are loaded.""" try: api = Api(url, token=token, timeout=timeout) @@ -207,15 +219,15 @@ def check_flow_blueprints(url: str, timeout: int, token: Optional[str] = None) - blueprints = flow_api.list_blueprints() if blueprints and len(blueprints) > 0: - return True, f"Found {len(blueprints)} flow blueprint(s)" + return True, tr.t("cli.verify_system_status.flow_blueprints.found", count=len(blueprints)) else: - return False, "No flow blueprints found" + return False, tr.t("cli.verify_system_status.flow_blueprints.none") except Exception as e: - return False, f"Flow blueprints check error: {e}" + return False, tr.t("cli.verify_system_status.flow_blueprints.error", error=str(e)) -def check_flows(url: str, timeout: int, token: Optional[str] = None) -> Tuple[bool, str]: +def check_flows(url: str, timeout: int, tr, token: Optional[str] = None) -> Tuple[bool, str]: """Check if flow manager is responding.""" try: api = Api(url, token=token, timeout=timeout) @@ -224,13 +236,13 @@ def check_flows(url: str, timeout: int, token: Optional[str] = None) -> Tuple[bo flows = flow_api.list() # Success if we get a response (even if empty) - return True, f"Flow manager responding ({len(flows)} flow(s))" + return True, tr.t("cli.verify_system_status.flows.responding", count=len(flows)) except Exception as e: - return False, f"Flow manager check error: {e}" + return False, tr.t("cli.verify_system_status.flows.error", error=str(e)) -def check_prompts(url: str, timeout: int, token: Optional[str] = None) -> Tuple[bool, str]: +def check_prompts(url: str, timeout: int, tr, token: Optional[str] = None) -> Tuple[bool, str]: """Check if prompts are loaded.""" try: api = Api(url, token=token, timeout=timeout) @@ -248,15 +260,15 @@ def check_prompts(url: str, timeout: int, token: Optional[str] = None) -> Tuple[ ix = json.loads(values[0].value) if ix and len(ix) > 0: - return True, f"Found {len(ix)} prompt(s)" + return True, tr.t("cli.verify_system_status.prompts.found", count=len(ix)) else: - return False, "No prompts found" + return False, tr.t("cli.verify_system_status.prompts.none") except Exception as e: - return False, f"Prompts check error: {e}" + return False, tr.t("cli.verify_system_status.prompts.error", error=str(e)) -def check_library(url: str, timeout: int, token: Optional[str] = None) -> Tuple[bool, str]: +def check_library(url: str, timeout: int, tr, token: Optional[str] = None) -> Tuple[bool, str]: """Check if library service is responding.""" try: api = Api(url, token=token, timeout=timeout) @@ -266,13 +278,13 @@ def check_library(url: str, timeout: int, token: Optional[str] = None) -> Tuple[ docs = library_api.get_documents(user="trustgraph") # Success if we get a valid response (even if empty) - return True, f"Library responding ({len(docs)} document(s))" + return True, tr.t("cli.verify_system_status.library.responding", count=len(docs)) except Exception as e: - return False, f"Library check error: {e}" + return False, tr.t("cli.verify_system_status.library.error", error=str(e)) -def check_ui(url: str, timeout: int) -> Tuple[bool, str]: +def check_ui(url: str, timeout: int, tr) -> Tuple[bool, str]: """Check if Workbench UI is responding.""" try: if not url.endswith('/'): @@ -280,15 +292,15 @@ def check_ui(url: str, timeout: int) -> Tuple[bool, str]: resp = requests.get(f"{url}index.html", timeout=timeout) if resp.status_code == 200: - return True, "Workbench UI is responding" + return True, tr.t("cli.verify_system_status.ui.responding") else: - return False, f"UI returned status {resp.status_code}" + return False, tr.t("cli.verify_system_status.ui.status", status_code=resp.status_code) except requests.exceptions.Timeout: - return False, "UI connection timeout" + return False, tr.t("cli.verify_system_status.ui.timeout") except requests.exceptions.ConnectionError: - return False, "Cannot connect to UI" + return False, tr.t("cli.verify_system_status.ui.cannot_connect") except Exception as e: - return False, f"UI error: {e}" + return False, tr.t("cli.verify_system_status.ui.error", error=str(e)) def main(): @@ -300,6 +312,12 @@ def main(): formatter_class=argparse.RawDescriptionHelpFormatter, ) + parser.add_argument( + '--lang', + default=os.getenv("TRUSTGRAPH_LANG", "en"), + help='Language code for CLI output (default: $TRUSTGRAPH_LANG or en)' + ) + parser.add_argument( '--global-timeout', type=int, @@ -366,16 +384,19 @@ def main(): args = parser.parse_args() + tr = get_translator(args.lang) + # Create health checker checker = HealthChecker( global_timeout=args.global_timeout, check_timeout=args.check_timeout, retry_delay=args.retry_delay, - verbose=args.verbose + verbose=args.verbose, + translator=tr, ) print("=" * 60) - print("TrustGraph System Status Verification") + print(tr.t("cli.verify_system_status.title")) print("=" * 60) # print(f"Global timeout: {args.global_timeout}s") # print(f"Check timeout: {args.check_timeout}s") @@ -384,111 +405,119 @@ def main(): print() # Phase 1: Infrastructure - print("Phase 1: Infrastructure") + print(tr.t("cli.verify_system_status.phase_1")) print("-" * 60) if not checker.run_check( - "Pulsar", + tr.t("cli.verify_system_status.check_name.pulsar"), check_pulsar, args.pulsar_url, - args.check_timeout + args.check_timeout, + tr, ): - print("\n⚠️ Pulsar is not responding - other checks may fail") + print(f"\n⚠️ {tr.t('cli.verify_system_status.pulsar_not_responding')}") print() checker.run_check( - "API Gateway", + tr.t("cli.verify_system_status.check_name.api_gateway"), check_api_gateway, args.api_url, args.check_timeout, - args.token + tr, + args.token, ) print() # Phase 2: Core Services - print("Phase 2: Core Services") + print(tr.t("cli.verify_system_status.phase_2")) print("-" * 60) checker.run_check( - "Processors", + tr.t("cli.verify_system_status.check_name.processors"), check_processors, args.api_url, args.min_processors, args.check_timeout, - args.token + tr, + args.token, ) checker.run_check( - "Flow Blueprints", + tr.t("cli.verify_system_status.check_name.flow_blueprints"), check_flow_blueprints, args.api_url, args.check_timeout, - args.token + tr, + args.token, ) checker.run_check( - "Flows", + tr.t("cli.verify_system_status.check_name.flows"), check_flows, args.api_url, args.check_timeout, - args.token + tr, + args.token, ) checker.run_check( - "Prompts", + tr.t("cli.verify_system_status.check_name.prompts"), check_prompts, args.api_url, args.check_timeout, - args.token + tr, + args.token, ) print() # Phase 3: Data Services - print("Phase 3: Data Services") + print(tr.t("cli.verify_system_status.phase_3")) print("-" * 60) checker.run_check( - "Library", + tr.t("cli.verify_system_status.check_name.library"), check_library, args.api_url, args.check_timeout, - args.token + tr, + args.token, ) print() # Phase 4: UI (optional) if not args.skip_ui: - print("Phase 4: User Interface") + print(tr.t("cli.verify_system_status.phase_4")) print("-" * 60) checker.run_check( - "Workbench UI", + tr.t("cli.verify_system_status.check_name.workbench_ui"), check_ui, args.ui_url, - args.check_timeout + args.check_timeout, + tr, ) print() # Summary print("=" * 60) - print("Summary") + print(tr.t("cli.verify_system_status.summary")) print("=" * 60) total_checks = checker.checks_passed + checker.checks_failed - print(f"Checks passed: {checker.checks_passed}/{total_checks}") - print(f"Checks failed: {checker.checks_failed}/{total_checks}") - print(f"Total time: {checker.elapsed()}") + print(tr.t("cli.verify_system_status.checks_passed", passed=checker.checks_passed, total=total_checks)) + print(tr.t("cli.verify_system_status.checks_failed", failed=checker.checks_failed, total=total_checks)) + print(tr.t("cli.verify_system_status.total_time", elapsed=checker.elapsed())) if checker.checks_failed == 0: - print("\n✓ System is healthy!") + print(f"\n✓ {tr.t('cli.verify_system_status.system_healthy')}") sys.exit(0) else: - print(f"\n✗ System has {checker.checks_failed} failing check(s)") + print(f"\n✗ {tr.t('cli.verify_system_status.system_failing', failed=checker.checks_failed)}") sys.exit(1) diff --git a/trustgraph-flow/trustgraph/gateway/endpoint/i18n.py b/trustgraph-flow/trustgraph/gateway/endpoint/i18n.py new file mode 100644 index 00000000..67cd3c13 --- /dev/null +++ b/trustgraph-flow/trustgraph/gateway/endpoint/i18n.py @@ -0,0 +1,45 @@ +import logging + +from aiohttp import web + +from trustgraph.i18n import get_language_pack + +logger = logging.getLogger("endpoint") +logger.setLevel(logging.INFO) + + +class I18nPackEndpoint: + + def __init__(self, endpoint_path: str, auth): + self.path = endpoint_path + self.auth = auth + self.operation = "service" + + async def start(self): + pass + + def add_routes(self, app): + app.add_routes([ + web.get(self.path, self.handle), + ]) + + async def handle(self, request): + logger.debug(f"Processing i18n pack request: {request.path}") + + token = "" + try: + ht = request.headers["Authorization"] + tokens = ht.split(" ", 2) + if tokens[0] != "Bearer": + return web.HTTPUnauthorized() + token = tokens[1] + except Exception: + token = "" + + if not self.auth.permitted(token, self.operation): + return web.HTTPUnauthorized() + + lang = request.match_info.get("lang") or "en" + pack = get_language_pack(lang) + + return web.json_response(pack) diff --git a/trustgraph-flow/trustgraph/gateway/endpoint/manager.py b/trustgraph-flow/trustgraph/gateway/endpoint/manager.py index ff92dca2..fb8b0b76 100644 --- a/trustgraph-flow/trustgraph/gateway/endpoint/manager.py +++ b/trustgraph-flow/trustgraph/gateway/endpoint/manager.py @@ -7,6 +7,7 @@ from . stream_endpoint import StreamEndpoint from . variable_endpoint import VariableEndpoint from . socket import SocketEndpoint from . metrics import MetricsEndpoint +from . i18n import I18nPackEndpoint from .. dispatch.manager import DispatcherManager @@ -23,6 +24,10 @@ class EndpointManager: } self.endpoints = [ + I18nPackEndpoint( + endpoint_path = "/api/v1/i18n/packs/{lang}", + auth = auth, + ), MetricsEndpoint( endpoint_path = "/api/metrics", prometheus_url = prometheus_url, diff --git a/trustgraph/trustgraph/trustgraph_version.py b/trustgraph/trustgraph/trustgraph_version.py new file mode 100644 index 00000000..b08ba8d4 --- /dev/null +++ b/trustgraph/trustgraph/trustgraph_version.py @@ -0,0 +1 @@ +__version__ = "2.2.999"