סוגי מקורות¶
מודל הביצוע¶
כל שאילתה מבוצעת בסופו של דבר דרך מנוע הפדרציה, המספק פדרציה על פני כל המקורות. המקורות מתחלקים לשלוש קטגוריות בהתאם לקישוריות שלהם. [tool-verified: provisa/core/models.py lines 84–132] (REQ-550)
| קטגוריה | יש דרייבר ישיר | יש מחבר מפודרר | דוגמאות |
|---|---|---|---|
| תמיכה ישירה | כן | כן | PostgreSQL, MySQL, MariaDB, SingleStore, SQL Server, Oracle, DuckDB |
| פדרציה בלבד | לא | כן | Redshift, Druid, Exasol, Hive, Iceberg, Delta Lake, Hive (S3-backed) |
| קריאה ישירה (עותק משוכפל) | כן | כן | Snowflake, Databricks, ClickHouse — הדרייבר קורא נתונים ומנחית עותק משוכפל; השאילתות רצות מול העותק המשוכפל במנוע הפעיל |
| מטריאליזציה → פדרציה | לא | לא | REST/OpenAPI, remote GraphQL, gRPC, Neo4j Cypher, SPARQL, WebSocket, RSS, CSV, SQLite, Parquet, Ingest (push receiver), GovData, SharePoint, Splunk |
מקורות מסוג תמיכה ישירה מבצעים שאילתות חד-מקוריות דרך הדרייבר הילידי שלהם (מתחת ל-100ms), תוך עקיפת מנוע הפדרציה (REQ-027, REQ-229). הם שומרים על תמיכה מלאה במחבר ומשתתפים בפדרציה כשהם מוצטרפים (joined) עם מקורות אחרים (REQ-028).
מקורות מסוג פדרציה בלבד נשאלים תמיד דרך שכבת הפדרציה. לא קיים דרייבר ישיר (REQ-229).
למקורות מסוג קריאה ישירה (עותק משוכפל) יש DirectDriver שקורא מהמחסן באופן ילידי (Arrow-native היכן שזמין), מנחית עותק משוכפל למחסן המטריאליזציה של המנוע הפעיל, ולאחר מכן השאילתות רצות מול אותו עותק משוכפל. ראו Warehouses as Named Sources.
למקורות מטריאליזציה אין מחבר מפודרר. Provisa שולפת את הנתונים שלהם (בעת ההפעלה או בזמן השאילתה) ושומרת אותם במטמון כ-Parquet ב-S3 או ב-PostgreSQL, כך שהם נגישים למנוע הפדרציה לצורך שאילתות חוצות מקורות (REQ-309).
כל המקורות¶
מסמך עזר לכל סוג מקור שנתמך על ידי Provisa. "דרייבר ישיר" פירושו ששאילתות חד-מקוריות מבוצעות מול המקור באופן ילידי (מתחת ל-100ms) (REQ-027). "שם המחבר" הוא המחבר המפודרר שבו נעשה שימוש כאשר המקור משתתף ב-JOIN רב-מקורי (REQ-028). [tool-verified: provisa/core/source_registry.py SOURCE_TO_DIALECT; provisa/federation/trino_connectors.py trino_connector_name]
RDBMS¶
| סוג מקור | דרייבר ישיר | שם המחבר | דיאלקט | מוטציות |
|---|---|---|---|---|
postgresql |
asyncpg | postgresql | postgres | כן |
mysql |
aiomysql | mysql | mysql | כן |
mariadb |
aiomysql | mariadb | mysql | כן |
singlestore |
— | singlestore | singlestore | מפודרר |
sqlserver |
aioodbc | sqlserver | tsql | כן |
oracle |
oracledb | oracle | oracle | כן |
duckdb |
duckdb | memory | duckdb | כן |
cockroachdb |
asyncpg (pg wire) | postgresql | postgres | כן |
yugabytedb |
asyncpg (pg wire) | postgresql | postgres | כן |
greenplum |
asyncpg (pg wire) | postgresql | postgres | כן |
tidb |
aiomysql (mysql wire) | mysql | mysql | כן |
מסדי נתונים תואמי-wire עושים שימוש חוזר ב-JDBC driver, בדרייבר האסינכרוני הילידי ובדיאלקט של ה-wire הבסיסי — CockroachDB, YugabyteDB ו-Greenplum רוכבים על ה-wire של PostgreSQL; TiDB רוכב על ה-wire של MySQL. הם זקוקים רק לרשומות רישום, ללא קוד מחבר חדש. [tool-verified: provisa/core/source_registry.py _PG_WIRE_TYPES, _MYSQL_WIRE_TYPES] (REQ-950)
firebird (Firebird 3/4/5) ו-airport (Arrow Flight server) הם סוגי מקור רשומים המושגים במקום דרך תוספי הקהילה של DuckDB כאשר DuckDB הוא המנוע הפעיל — ללא דרייבר ישיר, ללא מחבר מפודרר. [tool-verified: provisa/core/models.py lines 44, 93] (REQ-899)
מחסני נתונים בענן¶
[tool-verified: executor/drivers/snowflake.py, executor/drivers/databricks.py, executor/drivers/registry.py]
| סוג מקור | דרייבר ישיר | שם המחבר | דיאלקט | מוטציות | הערות |
|---|---|---|---|---|---|
snowflake |
SnowflakeDriver | snowflake | snowflake | מפודרר | קורא באמצעות snowflake-connector-python; מנחית עותק משוכפל; account/warehouse/role ב-federation_hints (REQ-988) |
bigquery |
— | bigquery | bigquery | מפודרר | אין DirectDriver; מושג דרך מנוע הפדרציה או ATTACH של מנוע BigQuery |
databricks |
DatabricksDriver | delta_lake | databricks | מפודרר | קורא באמצעות databricks-sql-connector (Cloud Fetch, Arrow); מנחית עותק משוכפל; http_path נדרש ב-federation_hints (REQ-987) |
redshift |
— | redshift | redshift | מפודרר | — |
fabric |
MssqlWarehouseDriver | — | tsql | מפודרר | Microsoft Fabric Warehouse; T-SQL מעל TDS, אימות Azure AD; מנחית עותק משוכפל (REQ-995) |
synapse |
MssqlWarehouseDriver | — | tsql | מפודרר | Azure Synapse SQL; T-SQL מעל TDS, אימות Azure AD; מנחית עותק משוכפל (REQ-995) |
trino |
SQLAlchemyDriver | — | — | מפודרר | קריאה של קואורדינטור Trino/Presto מרוחק דרך דיאלקט ה-trino של SQLAlchemy; מנחית עותק משוכפל על כל מנוע (REQ-994) |
אנליטיקה / OLAP¶
[tool-verified: executor/drivers/clickhouse.py]
| סוג מקור | דרייבר ישיר | שם המחבר | דיאלקט | מוטציות | הערות |
|---|---|---|---|---|---|
clickhouse |
ClickHouseDriver | clickhouse | clickhouse | מפודרר | קורא באמצעות clickhouse-connect (HTTP); secure: "true" ב-federation_hints עבור TLS (REQ-986) |
druid |
— | druid | druid | לא | — |
exasol |
— | exasol | exasol | לא | — |
elasticsearch |
— | elasticsearch | — | לא | מאפייני המחבר מגיעים מ-DSL המיפוי של הסוג [tool-verified: trino_connectors.py:309] |
pinot |
— | pinot | — | לא | מחבר pinot של Trino; pinot.controller-urls = host:port של בקר ה-Pinot [tool-verified: trino_connectors.py:199] |
Data Lake / פורמטי טבלה פתוחים¶
סוגי המקור הבאים הם פדרציה-בלבד — ללא דרייבר ישיר, ללא דיאלקט. [tool-verified: LAKE_ONLY_SOURCES in provisa/core/source_registry.py] (REQ-229)
| סוג מקור | שם המחבר | Time Travel | הערות |
|---|---|---|---|
iceberg |
iceberg | כן (ארגומנט as_of, REQ-372) |
— |
delta_lake |
delta_lake | כן (ארגומנט as_of, REQ-372) |
— |
hive |
hive | לא | — |
hive_s3 |
hive | לא | Hive מגובה-S3 |
NoSQL¶
ל-mongodb, cassandra ו-redis יש מחברי Trino (redis בונה את המאפיינים שלו מ-DSL המיפוי של הסוג). [tool-verified: provisa/federation/trino_connectors.py; provisa/core/models.py] (REQ-017, REQ-1097)
| סוג מקור | שם המחבר | מוטציות |
|---|---|---|
mongodb |
mongodb | לא |
cassandra |
cassandra | לא |
redis |
redis | לא |
סטרימינג¶
| סוג מקור | מנגנון | מוטציות |
|---|---|---|
kafka |
מחבר Kafka מפודרר; סכמה דרך Confluent Schema Registry (Avro, Protobuf, JSON Schema), הגדרה ידנית, או הסקה מדגמית (REQ-147, REQ-150) | Sink בלבד (REQ-176) |
websocket |
הזנת WebSocket חיצונית — התחברות, הרשמה, קבלת אירועים; התוצאות עוברות מטריאליזציה (REQ-338) | לא |
rss |
הזנת RSS 2.0 / Atom — בדיקה תקופתית (poll), סימון מים לפי pubDate/updated; התוצאות עוברות מטריאליזציה (REQ-342, REQ-343) | לא |
Push Receiver¶
| סוג מקור | מנגנון | מוטציות |
|---|---|---|
ingest |
שירותים חיצוניים שולחים POST של אירועי JSON; התוצאות עוברות מטריאליזציה (REQ-331, REQ-335) | לא |
גרף וסמנטיקה¶
| סוג מקור | מנגנון | מוטציות |
|---|---|---|
neo4j |
Cypher דרך HTTP API, התוצאות נשמרות במטמון ב-PostgreSQL (REQ-295) | לא |
sparql |
POST של SPARQL 1.1, התוצאות נשמרות במטמון ב-PostgreSQL (REQ-297) | לא |
מבוססי קובץ¶
שני מנגנונים מכסים קבצים. שניהם משתמשים בשדה path במקום host/port. [tool-verified: provisa/core/models.py] (REQ-553)
מקורות חד-קובציים — sqlite, csv, parquet מפנים את path לקובץ בודד.
| סוג מקור | תעבורות | מוטציות |
|---|---|---|
sqlite |
מקומי | כן |
csv |
מקומי | לא |
parquet |
מקומי, s3:// |
לא |
דליים (buckets) פרטיים דורשים אישורים (region ומפתחות AWS מהסביבה). עבור CSV מעל s3:// או http(s)://, או כדי לרשום קבצים רבים בבת אחת, השתמשו במקור files. [tool-verified: provisa/file_source/source.py]
מקור files — מפנה את path ל-glob, סורק אותו רקורסיבית, ורושם את הספרייה כקטלוג מפודרר של טבלאות. הוא קורא פורמטים רבים על פני תעבורות רבות; הקבוצות שלהלן מגיעות ממחבר הקבצים (kenstott/calcite fork). [tool-verified: provisa/core/catalog.py files branch and provisa/core/models.py SOURCE_TO_CONNECTOR; format and transport lists from the calcite file adapter — FileSchema.java, storage/StorageProviderFactory.java]
| פורמטים | תעבורות |
|---|---|
| CSV, TSV, JSON, YAML, Excel (XLS/XLSX), Parquet, Arrow, ומסמכים המומרים לטבלאות — HTML, Markdown, DOCX, PPTX | מערכת קבצים מקומית, HTTP(S), s3://, hdfs://, ftp:///ftps://, sftp://, iceberg://, SharePoint (REST ו-Microsoft Graph) |
- id: sales_files
type: files
path: s3://bucket/sales/**/*.csv # glob; local and http(s):// also supported
Observability ואחרים¶
ל-prometheus יש מחבר Trino (מאפיינים הנבנים מ-DSL המיפוי של הסוג). google_sheets הוא סוג מקור רשום ללא מחבר Trino, ועובר מטריאליזציה דרך צינור המטמון של ה-API. [tool-verified: provisa/federation/trino_connectors.py:314; provisa/core/models.py lines 87–88]
| סוג מקור | שם המחבר | מוטציות |
|---|---|---|
google_sheets |
— (מטריאליזציה) | לא |
prometheus |
prometheus | לא |
מחברי SaaS ארגוניים¶
SharePoint ו-Splunk נרשמים דרך מחברי Apache Calcite (kenstott/calcite fork). לאף אחד מהם אין דרייבר ישיר — Provisa מבצעת מטריאליזציה של השורות שלהם על ידי הפעלת שרת ה-pgwire המצורף של המחבר (pgwire-sharepoint, pgwire-splunk), התחברות אליו כנקודת קצה גנרית של PostgreSQL, והנחתת השורות למחסן המטריאליזציה לצורך פדרציה (REQ-954). שני המחברים מפעילים תמיד התאמת שמות שאינה תלוית רישיות, בהתאמה לסמנטיקה שאינה תלוית-רישיות של כל מוצר (REQ-725, REQ-730). [tool-verified: provisa/core/models.py lines 99–100; provisa/federation/trino_connectors.py lines 223–286]
sharepoint¶
רשימות SharePoint נמנות כסכמות וחשופות כטבלאות ניתנות לשאילתה (REQ-726, REQ-731). שתי שיטות אימות: CLIENT_CREDENTIALS (ברירת מחדל) ומבוססת-תעודה (certificate) דרך תעודת PFX (REQ-727). ערכי סוד ב-mapping נפתרים דרך מנוע הסודות לפני שהם מגיעים למחבר (REQ-729). [tool-verified: provisa/federation/trino_connectors.py lines 230–252]
| שדה מקור | מאפיין מחבר | הערות |
|---|---|---|
base_url או host |
site-url |
כתובת URL של אתר SharePoint |
username |
client-id |
מזהה client של אפליקציית Azure |
password |
client-secret |
סוד client של אפליקציית Azure |
database |
tenant-id |
UUID דייר (tenant) של Azure |
mapping.auth_type |
auth-type |
CLIENT_CREDENTIALS (ברירת מחדל) או CERTIFICATE |
mapping.certificate_path |
certificate-path |
נתיב PFX כאשר auth_type: CERTIFICATE |
mapping.certificate_password |
certificate-password |
סיסמת PFX |
כאשר המחבר לא חושף information_schema.columns, יש לרשום את הטבלה עם הגדרות עמודה מפורשות (המתקבלות מ-Microsoft Graph API) דרך המוטציה registerTable (REQ-732).
- id: hr-sharepoint
type: sharepoint
base_url: https://kenstott.sharepoint.com
username: ${env:SP_CLIENT_ID}
password: ${env:SP_CLIENT_SECRET}
database: ${env:SP_TENANT_ID}
mapping:
auth_type: CLIENT_CREDENTIALS
splunk¶
תוצאות חיפוש Splunk ניתנות לשאילתה כטבלאות (לדוגמה internal_server) (REQ-721). כתובת ה-URL של המחבר מגיעה מ-base_url, או נבנית כ-https://{host}:{port} עם פורט ברירת מחדל 8089 (REQ-722). אימות: כאשר mapping.use_token הוא true (ברירת המחדל), password מועבר כאסימון ה-API; כאשר false, username ו-password מועברים כאישורים נפרדים (REQ-723). [tool-verified: provisa/federation/trino_connectors.py lines 262–286]
| שדה מקור | מאפיין מחבר | הערות |
|---|---|---|
base_url / host + port |
url |
base_url, אחרת https://host:port (ברירת מחדל לפורט 8089) |
password |
token או password |
אסימון כאשר use_token: true |
username |
user |
רק כאשר use_token: false |
database |
app |
הגבלה לאפליקציית Splunk מסוימת |
mapping.datamodel_filter |
datamodel-filter |
סינון למודל נתונים מסוים |
mapping.disable_ssl_validation |
disable-ssl-validation |
עבור תעודות בחתימה עצמית (REQ-724) |
- id: ops-splunk
type: splunk
host: splunk
port: 8089
password: ${env:SPLUNK_TOKEN}
mapping:
use_token: true
disable_ssl_validation: true
מקורות API¶
רישום כל נקודת קצה HTTP כטבלה ניתנת לשאילתה. [tool-verified: provisa/core/models.py SourceType enum] (REQ-314, REQ-307, REQ-322)
| סוג API | גילוי | הסקת עמודות |
|---|---|---|
openapi |
ניתוח מפרט OpenAPI (REQ-314, REQ-316) | פרימיטיבים → ילידי, אובייקטים → JSONB |
graphql_remote |
Schema introspection (REQ-307, REQ-308) | פרימיטיבים → ילידי, אובייקטים → JSONB |
grpc_remote |
Server reflection (REQ-322, REQ-325) | פרימיטיבים → ילידי, אובייקטים → JSONB |
תגובות API נשלפות, נשמרות במטמון ב-PostgreSQL (TTL הניתן להגדרה), וחשופות כטיפוסי GraphQL (REQ-309, REQ-318, REQ-327). טבלאות שנשמרו במטמון משתתפות בשאילתות מפודררות כמו כל מקור אחר (REQ-313).
כללי JSONB: עמודות מורכבות (אובייקטים, מערכים) המאוחסנות כ-JSONB אינן ניתנות לסינון (REQ-119). גישה לתת-שדה משתמשת בחילוץ ->> ב-SQL (REQ-151). קשרים (relationships) מוצהרים בין טבלאות באמצעות עמודות FK סקלריות — עמודות blob מסוג JSONB אינן יעדי join. השתמשו בקידום JSONB (JSONB promotion) כדי להמיר שדות מקוננים לעמודות סקלריות ילידיות כאשר נדרש לסנן או להצטרף (join) אליהן (REQ-119).
GovData¶
נתונים פתוחים של ממשלת ארה"ב. הגישה מחולקת לפי קיבוץ נושאים. [tool-verified: provisa/core/models.py lines 543–609]
כל מקור govdata בוחר נושא אחד. אותו נושא קובע אילו סכמות GovData חשופות. הסכמות ref ו-geo נכללות תמיד כסכמות מקשרות (linker schemas) — הן אינן מופיעות ברשימה לפי נושא אך תמיד נוכחות. [tool-verified: provisa/core/models.py line 562–563 comment]
| נושא | סכמות חשופות |
|---|---|
COMMERCE |
sec, patents |
ECONOMY |
econ |
EDUCATION |
census, edu |
HEALTH |
health |
CYBER |
cyber_threat, cyber_vuln |
PUBLIC_SAFETY |
crime |
ENVIRONMENT |
lands |
WEATHER |
weather |
GOVERNMENT |
fedregister, fec |
ALL |
כל סכמה שלעיל |
sources:
- id: federal-commerce
type: govdata
subject: COMMERCE
domain_id: federal-analytics
description: U.S. commerce and securities data
| שדה | חובה | ברירת מחדל | תיאור |
|---|---|---|---|
id |
כן | — | מזהה ייחודי |
subject |
כן | — | אחד מערכי הנושא שלעיל |
domain_id |
כן | — | הדומיין שאליו שייך מקור זה |
description |
לא | "" |
תיאור קריא לבני אדם |
בודקי איכות נתונים (REQ-1443)¶
בודק איכות נתונים הוא סוג מקור, לא תת-מערכת. פלט הסריקה שלו הוא נתונים: תוצאת בדיקה היא תצפית, כך שהיא עוברת דרך נתיב המקור הרגיל ויורשת קדנס (cadence), רעננות (freshness), אירועים, Data Lineage, ממשל, RLS, grid וייצוא מכל מקור אחר. [tool-verified: provisa/core/models.py lines 110–116 SourceType.soda, SourceType.great_expectations; provisa/events/source_loader.py make_dq_loader]
שניים נתמכים, והבחירה היא בחירת רישוי לא פחות מבחירת פיצ'ר.
| סוג מקור | דיאלקט חוזה (Contract) | תוסף | רישיון | מישור ענן מאוחסן |
|---|---|---|---|---|
soda |
Soda contract YAML | pip install .[soda] (soda-postgres) |
Elastic License 2.0 | נדחה — ראו בהמשך |
great_expectations |
Expectation suite JSON | pip install .[gx] (great-expectations[postgresql]) |
Apache 2.0 | מותר |
Elastic License 2.0 אוסר לספק את התוכנה לצדדים שלישיים כשירות מאוחסן או מנוהל, והרצת Soda בתוך מישור ה-SaaS בשם דייר (tenant) היא בדיוק זה. config/capabilities.yaml נושא את החלוקה כ-cloud_eligible: false על האפשרות soda, והמישור המאוחסן קורא את הדגל הזה. פריסה מאוחסנת שרוצה Soda מגיעה לנקודת קצה של Soda המסופקת על ידי המפעיל (operator) ומורצת על ידיו. [tool-verified: config/capabilities.yaml lines 197–203]
Provisa לא מספקת (vendors) ולא מקשרת (links) שום דבר. הסריקה רצה בתוך פרשן ילד (child interpreter) (python -m provisa.dq.worker), שהוא המקום היחיד שבו soda_core או great_expectations מיובאים, כך שבודק source-available לעולם לא מגיע לתהליך השרת, וקריסת בודק הורגת תת-תהליך (subprocess) ולא את לולאת האירועים (event loop). [tool-verified: provisa/dq/runner.py build_command, run_contract]
המקור מצביע על נקודת הקצה של pgwire של Provisa עצמה. זה מה שמאפשר לדרייבר postgres אחד לבדוק טבלה מגובה-Snowflake או מגובה-Iceberg: הבודק סורק את התצוגה המפודררת, לא את המערכת שמתחת. מכיוון שהמדיניות חלה על אותו חיבור, זהות הסריקה מוצהרת ולא נורשת — קבוצת שורות מסוננת אסור לה בשום פנים ואופן לגרום לבדיקה שעוברת בשקט.
sources:
- id: dq
type: soda
domain_id: sales-analytics
description: Soda contract scans over the governed estate
mapping:
host: localhost
port: 5439 # Provisa's pgwire endpoint
database: provisa
user: dq_scanner # the scan identity, declared explicitly
password: ${env:PROVISA_DQ_PASSWORD}
טבלת תוצאות אחת לכל חוזה, והחוזה הוא כל הרישום. הטבלה נושאת את dq_contract — טקסט החוזה מילה במילה — ושום דבר נוסף על צורתה. עמודות, watermark וקידומים כולם נגזרים. [tool-verified: provisa/dq/registration.py derive_checker_table]
tables:
- source_id: dq
schema_name: quality
table_name: orders_scan
domain_id: sales-analytics
change_signal: ttl_probe
cache_ttl: 3600
columns:
- name: scan_id # declared only to carry visible_to; replaced at parse
visible_to: [analyst, admin]
dq_contract: |
dataset: provisa/sales/orders
columns:
- name: customer_id
checks:
- missing:
threshold:
metric: percent
must_be_less_than: 1
checks:
- row_count:
must_be_greater_than: 0
מה שהרישום גוזר מהטקסט הזה:
- Data Lineage. החוזה כבר נוקב בשם ערכת הנתונים היעד שלו, כך שהרישום מנתח אותו באותו אופן שבו
extract_inputsמנתח SQL (REQ-939) ומפענח אותו לטבלה המנוהלת. הגדרה אחת, ללא עותק שני שעלול לסטות. חוזה הנוקב בשם ערכת נתונים לא-מנוהלת נכשל בקול רם בזמן הרישום במקום להנחית שורות שאף אחד לא ביקש. - עמודות. מעטפת התוצאה שייכת לבודק, לא למפעיל — 16 עמודות מסופקות, מ-
scan_idועדdiagnostics. עמודות מוצהרות נקראות רק עבור ה-visible_toשלהן, שחייב להיות פה אחד, ולאחר מכן מוחלפות. [tool-verified:provisa/dq/results.py_ENVELOPE,results_columns] - Watermark.
scan_timeהופך ל-watermark, מה שהופך את ההנחתה ל-append (REQ-982). היסטוריית סריקות מצטברת ללא תת-מערכת היסטוריה. - קידומים.
freshness_max_timestampו-dataset_rows_testedמקודמים מתוך ה-jsonbdiagnosticsכעמודות מוקלדות (REQ-119). ניתן להוסיף עוד באותו אופן שבו עושים זאת בכל עמודת jsonb אחרת. [tool-verified:provisa/dq/results.pyDQ_PROMOTIONS]
התזמון (Timing) אינו מוסיף שדות חדשים. change_signal יחד עם cache_ttl נותנים את קדנס הבדיקה (poll cadence); mv_debounce_quiet ו-mv_debounce_max_delay מקפלים פרץ עליון (upstream burst) לסריקה אחת (REQ-963); דרגת לוח שנה (calendar grain) הופכת אותה לתקופתית (REQ-962); expected_events עוצר את הסריקה עד שהקלטים שלה טריים לאורך החלון (REQ-961). לולאת ה-poll היא מתזמן הסריקה.
outcome הוא אחד מ-pass, fail, warn, error, skipped. אף אחד מהם אינו פסק דין — אכיפה, אם רוצים, היא הצהרה נפרדת מאוחר יותר: preflight או MV מעל התוצאות שהונחתו. מכיוון שתצפית שהונחתה אינה נושאת מחויבות דטרמיניזם (REQ-964), בדיקות לא-דטרמיניסטיות קבילות כאן שלעולם לא יכלו לשבת על שער preflight — ציון אנומליה, שינוי בחלון נגרר, רעננות מול עכשיו.
החוזה נכתב בממשק המשתמש, במשטח עריכת הטבלה, בפאנל איכות הנתונים, וטקסט החוזה הגולמי שם הוא תמיד מקור האמת. הרצה יבשה (dry run) מבצעת את החוזה מול הטבלה החיה ומציגה את התוצאות מבלי להנחית אותן — כך תופסים חוזה ששם ערכת הנתונים שלו פוענח למקום בלתי צפוי, ואחרת היה מנחית רק שורות עוברות.
מחברים מותאמים אישית (REQ-1177)¶
מנועי הפדרציה הילידיים — Postgres, DuckDB ו-ClickHouse — משיגים נגישות לסוג מקור חדש כאשר מפעיל (operator) מצהיר על מחבר עבורו ב-config/custom_connectors.yaml. לא נדרש קוד. [tool-verified: provisa/federation/custom_connectors.py load_custom_connectors; provisa/federation/engine.py build_pg_engine, build_duckdb_engine, build_clickhouse_engine]
הרחבת מחברים כשלעצמה קדמה לזה. מנוע Trino ניתן להרחבה זה מכבר בשכבה שלו — מחבר JDBC גנרי אחד שמפורמט לפי סוג מקור, גוף .properties של קטלוג לכל סוג, ותוספי מחבר Trino מותאמים אישית משל Provisa (Splunk, SharePoint, Calcite). [tool-verified: provisa/federation/trino_connectors.py _TrinoJdbcConnector, _TRINO_JDBC_TYPES; trino/plugins/trino-splunk, trino/plugins/trino-sharepoint, trino/plugins/trino-calcite] REQ-1177 מביא את אותה הרחבה מונעת-קונפיגורציה לשני המנועים הילידיים, ללא-אשכול (no-cluster), שקודם נשאו סט מחברים קבוע.
הקונפיגורציה נשלחת ריקה. מחברים מובנים מכסים נגישות מוכנה-מהקופסה; כל מה שבקובץ הזה נכתב על ידי המפעיל. [tool-verified: config/custom_connectors.yaml line 52: connectors: []] הגדירו PROVISA_CUSTOM_CONNECTORS כדי להצביע על נתיב אחר (שימושי לבדיקות).
סוגי מתאר (Descriptor)¶
| מנוע | סוג | מנגנון | מה המתאר מספק |
|---|---|---|---|
postgres |
pg_fdw |
SQL/MED (תקן ISO) | extension, server_options, user_mapping, supports_import, table_options, remote_schema |
duckdb |
duckdb_attach |
INSTALL/LOAD + ATTACH | extension, probe_symbol, attach_template, remote_schema |
duckdb |
duckdb_scan |
INSTALL/LOAD + תצוגת סורק | extension, probe_symbol, scan_template |
clickhouse |
clickhouse_database |
CREATE DATABASE ENGINE=… (חושף אוטומטית כל טבלה מרוחקת) |
ch_engine, engine_template |
clickhouse |
clickhouse_table |
CREATE TABLE ENGINE=… לכל טבלה (עמודות מהרישום) |
ch_engine, engine_template (עשוי לשאת {table}) |
clickhouse |
clickhouse_scan |
CREATE TABLE ENGINE=…, ClickHouse מסיק את הסכמה |
ch_engine, engine_template |
Postgres הוא גנרי. SQL/MED הוא תקן ISO, כך שכל FDW תואם חולק את אותה צורת DDL: CREATE SERVER … FOREIGN DATA WRAPPER <fdw> OPTIONS(…), אופציונלית CREATE USER MAPPING, ואז או IMPORT FOREIGN SCHEMA (כאשר supports_import: true) או CREATE FOREIGN TABLE מפורש לכל טבלה (כאשר false). מתאר pg_fdw מספק רק את השונות הספציפית ל-FDW — שם התוסף, מפתחות אפשרויות שרת, מפתחות user-mapping, דגל import, אפשרויות טבלה. כל FDW תואם-תקן ניתן אפוא להפעלה מקונפיגורציה בלבד. [tool-verified: provisa/federation/custom_connectors.py GenericPgFdwConnector.details lines 98–125]
DuckDB תומך בשני מנגנונים. תוסף החושף קטלוג דרך ATTACH משתמש ב-duckdb_attach; תוסף החושף פונקציית-טבלה לקריאה משתמש ב-duckdb_scan. תוסף שאינו מתאים לאף דפוס אינו נתמך. [tool-verified: provisa/federation/custom_connectors.py GenericDuckDbAttachConnector, GenericDuckDbScanConnector]
ClickHouse תומך בשלושה מנגנונים, אחד לכל צורת integration-engine: מנוע DATABASE יחסי החושף אוטומטית כל טבלה מרוחקת (clickhouse_database, למשל Redis/MySQL), מנוע לכל-טבלה שהעמודות שלו מסופקות מהרישום (clickhouse_table, למשל הגשר JDBC/ODBC — ה-engine_template עשוי לשאת placeholder בצורת {table} שהריצה (runtime) מקשרת), ומנוע file/lake/URL שהסכמה שלו מוסקת על ידי ClickHouse (clickhouse_scan, למשל HDFS/URL). SQLite (מנוע DATABASE, קובץ, ללא שרת) ו-Hudi (lakehouse, zero-copy) נשלחים מוכנים-מהקופסה. [tool-verified: provisa/federation/custom_connectors.py GenericClickHouseDatabaseConnector, GenericClickHouseTableConnector, GenericClickHouseScanConnector; provisa/federation/clickhouse_connectors.py ClickHouseSqliteConnector, ClickHouseHudiConnector] (REQ-1178)
ערך kind לא מוכר נכשל בקול רם בעת ההפעלה — טעות הקלדה במתאר אסור לה להשאיר בשקט סוג מקור בלתי נגיש. [tool-verified: provisa/federation/custom_connectors.py load_custom_connectors lines 178–197]
שערי בדיקה (Probe Gating)¶
הזמינות מאומתת בזמן ה-attach מול קטלוג הגילוי הסטנדרטי של כל מנוע:
- Postgres — בודק את
pg_extension, ואז אתpg_available_extensions. [tool-verified:provisa/federation/connector_duckdb.py_probe_pg_extensionlines 333–344] - DuckDB — מריץ
INSTALL/LOADובודק אתduckdb_functions()עבור ה-probe_symbolהמוצהר. [tool-verified:provisa/federation/connector_duckdb.py_DuckDBExtensionConnector.probelines 160–180] - ClickHouse — בודק את
system.table_enginesעבור ה-ch_engineהמוצהר; היעדרות מה-build נכשלת בקול רם. [tool-verified:provisa/federation/custom_connectors.py_probe_clickhouse_engine]
תוסף מוצהר שאינו ניתן להתקנה נכשל בקול רם. ללא דילוג שקט, ללא נפילה חזרה (fallback). מחבר שהבדיקה שלו נכשלת פשוט אינו פעיל עבור אותה פריסה.
משתני תבנית¶
כל ערך server_options, ערך user_mapping, attach_template, ו-scan_template יכולים להשתמש ב-placeholders מסוג {field}. שדות זמינים: [tool-verified: provisa/federation/custom_connectors.py _source_fields lines 53–63]
{id}, {host}, {port}, {database}, {username}, {password}, {path}, {schema_name}, {table_name}, בתוספת כל מפתח מ-federation_hints. תבניות attach של DuckDB מקבלות גם {alias} — כינוי הקטלוג הפנימי ש-Provisa מקצה למסד הנתונים המצורף.
תבנית המפנה לשדה לא מוכר נכשלת בקול רם בזמן ה-attach, וחושפת אי-התאמה בין מתאר למקור לפני ש-DDL שבור מגיע למנוע.
דוגמאות¶
Postgres — MongoDB דרך mongo_fdw (ללא ייבוא סכמה; עמודות מסופקות לכל טבלה)
# config/custom_connectors.yaml
connectors:
- engine: postgres
source_type: mongodb
kind: pg_fdw
extension: mongo_fdw
mechanism: attach_r
server_options:
address: "{host}"
port: "{port}"
user_mapping:
username: "{username}"
password: "{password}"
supports_import: false
table_options:
database: "{database}"
collection: "{table_name}"
DuckDB — קובצי Excel דרך read_xlsx (פונקציית-טבלה לסריקה)
- engine: duckdb
source_type: xlsx
kind: duckdb_scan
extension: excel
install_from_community: false
probe_symbol: read_xlsx
scan_template: "read_xlsx('{path}')"
[tool-verified: config/custom_connectors.yaml commented examples, lines 26–50]
עם מתאר כלשהו במקום, רישום מקור עם ה-source_type המוצהר מנותב דרך המחבר המותאם אישית, בכפוף לבדיקה מוצלחת. אין צורך בשינוי קונפיגורציה נוסף.
מחסנים כמקורות בעלי שם¶
Snowflake, Databricks ו-ClickHouse ניתנים לרישום כמקורות בעלי שם באופן בלתי תלוי במנוע הפדרציה הפעיל. [tool-verified: executor/drivers/snowflake.py (REQ-988), executor/drivers/databricks.py (REQ-987), executor/drivers/clickhouse.py (REQ-986)]
עם הרישום, Provisa קוראת את המחסן באמצעות ה-DirectDriver של המקור ומנחיתה עותק משוכפל למחסן המטריאליזציה של המנוע הפעיל. השאילתה רצה לאחר מכן מול אותו עותק משוכפל. זה שונה מהנתיב המסורתי בעל התמיכה הישירה (asyncpg, aiomysql) שבו המנוע נעקף לחלוטין — כאן המנוע עדיין מבצע את השאילתה, אך מול עותק משוכפל מקומי ולא דרך ה-wire למחסן בכל בקשה.
הקריאות הן Arrow-native היכן שהמחסן תומך בכך: Databricks משתמש ב-Cloud Fetch, Snowflake משתמש ב-fetch_arrow_table, ו-ClickHouse משתמש בממשק ה-HTTP העמודתי הילידי.
פרמטרי חיבור מורחבים שהשדות הסטנדרטיים host/port/username/password אינם יכולים לשאת נכנסים ל-federation_hints:
sources:
- id: my-databricks
type: databricks
host: my-workspace.azuredatabricks.net
password: ${env:DATABRICKS_TOKEN}
federation_hints:
http_path: /sql/1.0/warehouses/xxxx # required — the SQL Warehouse connection detail
- id: my-snowflake
type: snowflake
host: org.snowflakecomputing.com
username: svc_provisa
password: ${env:SNOWFLAKE_PASSWORD}
federation_hints:
account: myorg-myaccount # required — Snowflake account identifier
warehouse: COMPUTE_WH # optional — virtual warehouse to use
role: PROVISA_ROLE # optional — Snowflake role
- id: my-clickhouse
type: clickhouse
host: ch.example.com
port: 8123
database: analytics
username: default
password: ${env:CLICKHOUSE_PASSWORD}
federation_hints:
secure: "true" # optional — enables TLS on the HTTP interface
רישום כמקור בעל שם בלתי תלוי בבחירת אותו מחסן כמנוע הפדרציה. מקור Snowflake על מנוע DuckDB מנחית עותק משוכפל ל-DuckDB, לא ל-Snowflake.
נתוני object/lake בענן (קבצי parquet, csv, iceberg, delta_lake על S3 / GCS / R2) הם סוג מקור נפרד שמתחבר (attach) במקום כאשר למנוע הפעיל יש מחבר ATTACH לאותו סוג. לא מונחת עותק משוכפל — המנוע סורק את אחסון האובייקטים ישירות. אישורים (credentials) עבור מקורות אלה נכנסים אף הם ל-federation_hints:
sources:
- id: r2-events
type: parquet
path: s3://my-bucket/events/2026/*.parquet
federation_hints:
access_key_id: ${env:R2_ACCESS_KEY}
secret_access_key: ${env:R2_SECRET}
account_id: ${env:R2_ACCOUNT_ID} # Cloudflare R2 account (S3-compatible)
שדות קונפיגורציית מקור¶
כל המקורות חולקים סט משותף של שדות. [tool-verified: provisa/core/models.py Source class, lines 138–204]
| שדה | חובה | ברירת מחדל | תיאור |
|---|---|---|---|
id |
כן | — | מזהה ייחודי; אלפאנומרי עם מקפים/קווים תחתונים |
type |
כן | — | סוג מקור (ראו הטבלאות לעיל) |
host |
לא | "" |
Hostname או IP |
port |
לא | 0 |
מספר פורט |
database |
לא | "" |
שם מסד נתונים |
username |
לא | "" |
שם משתמש |
password |
לא | "" |
סיסמה; השתמשו ב-${env:VAR} לפתרון סוד |
path |
לא | null |
נתיב קובץ או URI ענן עבור מקורות מבוססי-קובץ ו-object/lake |
base_url |
לא | null |
כתובת URL בסיסית עבור מקורות OpenAPI |
pool_min |
לא | 1 |
גודל מינימלי של pool חיבורים (REQ-052) |
pool_max |
לא | 5 |
גודל מקסימלי של pool חיבורים (REQ-052) |
use_pgbouncer |
לא | false |
ניתוב חיבורים דרך PgBouncer (REQ-053) |
pgbouncer_port |
לא | 6432 |
פורט PgBouncer (REQ-053) |
cache_enabled |
לא | true |
הפעלת שמירה במטמון של תגובות API |
cache_ttl |
לא | null |
TTL של המטמון בשניות; יורש ברירת מחדל גלובלית כאשר null |
cache_catalog |
לא | null |
קטלוג מפודרר עבור מטמון ה-API; ברירת מחדל היא הקטלוג של המקור עצמו |
cache_schema |
לא | api_cache |
סכמה בתוך קטלוג המטמון |
naming_convention |
לא | null |
דריסת מוסכמת השמות הגלובלית עבור מקור זה (REQ-194) |
federation_hints |
לא | {} |
מאפייני session המועברים למנוע הפדרציה, ופרמטרי חיבור מורחבים עבור מקורות מחסן (REQ-278, REQ-281) |
mapping |
לא | {} |
הגדרות מחבר ספציפיות-סוג עבור מקורות NoSQL ו-SaaS (למשל auth_type של SharePoint, use_token של Splunk) (REQ-251) |
allowed_domains |
לא | [] |
הגבלת המקור לדומיינים ספציפיים; ריק = ללא הגבלה |
description |
לא | "" |
תיאור קריא לבני אדם |
מקורות Kafka¶
נושאי (topics) Kafka מוגדרים בנפרד תחת kafka_sources, ממופתחים לפי ה-id של מקור kafka רשום. [tool-verified: config/provisa.yaml lines 138–151] (REQ-147)
kafka_sources:
- id: kafka-support
topics:
- id: tickets
topic: support.tickets
domain_id: sales-analytics
description: "Inbound support tickets"
default_window: 1h
columns:
- name: id
- name: subject
- name: status
- name: created_at
| שדה | תיאור |
|---|---|
id |
חייב להתאים ל-id של מקור מסוג type: kafka |
topics[].id |
שם לוגי לנושא זה בתוך Provisa |
topics[].topic |
שם נושא Kafka |
topics[].domain_id |
הדומיין שאליו שייך נושא זה |
topics[].description |
תיאור קריא לבני אדם |
topics[].default_window |
חלון זמן ברירת מחדל עבור שאילתות מחולנות (windowed) (למשל 1h) (REQ-148) |
topics[].columns |
הגדרות עמודה עבור סכמת הנושא (REQ-150) |
נראות עמודות¶
השדה visible_to בכל עמודה הוא רשימת מזהי תפקיד (role) שיכולים לראות את אותה עמודה. [tool-verified: provisa/core/models.py Column class line 248; config/provisa.yaml lines 39–51]
columns:
- name: email
visible_to: [admin] # only admin role sees this column
- name: region
visible_to: [admin, analyst] # both roles see this column
עמודות שהושמטו מרשימת ה-visible_to של תפקיד לא מופיעות בסכמת ה-GraphQL של אותו תפקיד ולא ניתנות לשאילתה או להפניה במסננים (REQ-039).
קשרים (Relationships)¶
קשרים מחברים שתי טבלאות רשומות ומופיעים כשדות מקוננים ב-GraphQL. [tool-verified: provisa/core/models.py Relationship class lines 323–343; config/provisa.yaml lines 103–110] (REQ-019)
relationships:
- id: orders-to-customers
source_table_id: orders
target_table_id: customers
source_column: customer_id
target_column: id
cardinality: many-to-one
| שדה | חובה | תיאור |
|---|---|---|
id |
כן | מזהה ייחודי לקשר זה |
source_table_id |
כן | הטבלה הנושאת את המפתח הזר |
target_table_id |
כן | הטבלה שאליה מפנים; ריק עבור קשרים מחושבים |
source_column |
כן | עמודה בטבלת המקור |
target_column |
כן | עמודה בטבלת היעד; ריק עבור קשרים מחושבים |
cardinality |
כן | many-to-one או one-to-many (REQ-019) |
materialize |
לא | יצירה אוטומטית של Materialized View עבור joins חוצי-מקורות (REQ-158) |
refresh_interval |
לא | מרווח רענון MV בשניות (ברירת מחדל: 300) |
target_function_name |
לא | שם פונקציית DB עבור קשרים מחושבים |
function_arg |
לא | איזה ארגומנט פונקציה מקבל את ערך עמודת המקור |
alias |
לא | סוג קשר קריא לבני אדם (למשל WORKS_FOR) |
graphql_alias |
לא | קובע את שם שדה ה-SDL שקשר זה חושף על הטיפוס ההורה. כאשר נעדר, השם נגזר מ-field_name של טבלת היעד ומקרדינליות הקשר. [tool-verified: provisa/compiler/schema_gen.py:1050] |
disable_cypher |
לא | כאשר true, מוציא קשר זה מקשתות הגרף של Cypher |
source_json_key |
לא | חילוץ מפתח זה מעמודת המקור כאובייקט JSON לפני JOIN |
ערכי קרדינליות [tool-verified: provisa/core/models.py Cardinality enum, lines 79–81]:
many-to-one— כל שורת מקור ממופה לשורת יעד אחת (FK ל-PK)one-to-many— כל שורת מקור ממופה למספר שורות יעד (הפוך מלמעלה)
כללי אבטחה ברמת השורה¶
כללי RLS מזריקים משפטי WHERE בזמן השאילתה, בהיקף של תפקיד ואופציונלית של טבלה או דומיין. [tool-verified: provisa/core/models.py RLSRule class lines 391–395; config/provisa.yaml lines 128–131] (REQ-041)
rls_rules:
- table_id: orders # applies to orders table only
role_id: analyst
filter: "region = current_setting('provisa.user_region')"
- domain_id: sales-analytics # applies to every table in domain (REQ-402)
role_id: analyst
filter: "tenant_id = current_setting('provisa.tenant_id')"
כאשר קיים גם כלל ברמת-דומיין וגם כלל ברמת-טבלה עבור אותו תפקיד, הכלל ברמת-הטבלה גובר (REQ-403).
| שדה | חובה | תיאור |
|---|---|---|
table_id |
מותנה | הטבלה שעליה חל הכלל; בלעדי הדדית עם domain_id |
domain_id |
מותנה | הדומיין שעליו חל הכלל; חל על כל הטבלאות בדומיין (REQ-402) |
role_id |
כן | התפקיד שעליו חל כלל זה |
filter |
כן | פרדיקט SQL המוזרק לתוך WHERE; יכול להפנות למשתני session (REQ-041) |
פונקציות ו-Webhooks¶
פונקציות DB¶
מעקב אחר פונקציית מסד נתונים וחשיפתה כשאילתת GraphQL או מוטציה. [tool-verified: provisa/core/models.py Function class lines 423–438; config/provisa.yaml lines 152–164] (REQ-205)
מקורות מסד נתונים יכולים גם לגלות אוטומטית את הפרוצדורות המאוחסנות והפונקציות שלהם מקטלוג הספק (pg_proc, information_schema.routines, או שווי-ערך של הספק), ולבטל את הצורך ברישום ידני של כל אחת. הגילוי קורא prokind ו-provolatile: פונקציות immutable/stable נרשמות כיחסים (relations) מפורמטים (ארגומנטי הפרוצדורה הופכים לפרמטרי שאילתה, אותה צורה כמו טבלאות OpenAPI GET), ופרוצדורות volatile נרשמות כמוטציות/פונקציות במעקב. פרוצדורות שהתגלו זורמות דרך ממשל שלב-2 (Stage-2 governance) באותו אופן כמו כאלה שנרשמו ידנית. [tool-verified: provisa/api/admin/introspect.py:541, provisa/api/admin/introspect.py:593] (REQ-887)
functions:
- name: get_customers_by_region
source_id: sales-pg
schema: public
function_name: get_customers_by_region
returns: customers
domain_id: sales-analytics
description: "Returns customers filtered by region"
visible_to: [admin, analyst]
kind: query
arguments:
- name: p_region
type: String
| שדה | חובה | ברירת מחדל | תיאור |
|---|---|---|---|
name |
כן | — | שם שדה GraphQL |
source_id |
כן | — | המקור המכיל את הפונקציה |
schema |
לא | public |
סכמת מסד נתונים |
function_name |
כן | — | שם פונקציית מסד הנתונים בפועל |
returns |
כן | — | מזהה טבלה רשומה שהפונקציה מחזירה (REQ-207) |
arguments |
לא | [] |
רשימת הגדרות ארגומנט {name, type} (REQ-211) |
visible_to |
לא | [] |
תפקידים שיכולים לקרוא לפונקציה זו |
writable_by |
לא | [] |
תפקידים שיכולים לקרוא לזה כמוטציה |
domain_id |
לא | "" |
הדומיין שאליו שייכת פונקציה זו |
description |
לא | null |
תיאור שדה GraphQL |
kind |
לא | mutation |
"query" או "mutation" (REQ-205) |
Webhooks¶
חשיפת נקודת קצה HTTP חיצונית כשאילתת GraphQL או מוטציה. [tool-verified: provisa/core/models.py Webhook class lines 441–455; config/provisa.yaml lines 166–178] (REQ-209)
webhooks:
- name: notify_support
url: http://localhost:9999/notify
method: POST
timeout_ms: 3000
domain_id: sales-analytics
description: "Send a support notification"
visible_to: [admin]
kind: mutation
arguments:
- name: message
type: String
| שדה | חובה | ברירת מחדל | תיאור |
|---|---|---|---|
name |
כן | — | שם שדה GraphQL |
url |
כן | — | כתובת URL של נקודת הקצה של ה-webhook |
method |
לא | POST |
שיטת HTTP |
timeout_ms |
לא | 5000 |
timeout בקשה במילישניות |
returns |
לא | null |
מזהה טבלה רשומה, או null עבור טיפוס inline |
inline_return_type |
לא | [] |
רשימת שדות {name, type} עבור צורות החזרה מותאמות אישית (REQ-210) |
arguments |
לא | [] |
רשימת הגדרות ארגומנט {name, type} |
visible_to |
לא | [] |
תפקידים שיכולים לקרוא ל-webhook זה |
domain_id |
לא | "" |
הדומיין שאליו שייך webhook זה |
description |
לא | null |
תיאור שדה GraphQL |
kind |
לא | mutation |
"query" או "mutation" |
אימות (Authentication)¶
האימות מוגדר תחת המפתח auth. [tool-verified: provisa/core/models.py AuthConfig class lines 467–477] (REQ-120)
| ספק | תיאור |
|---|---|
none |
ללא אימות; כל הבקשות מטופלות כ-default_role |
firebase |
Firebase Authentication; דורש project_id ו-service_account_key (REQ-121) |
keycloak |
Keycloak OIDC (REQ-122) |
oauth |
OAuth 2.0 גנרי (REQ-123) |
simple |
שם משתמש/סיסמה ללא ספק חיצוני (REQ-124) |
auth:
provider: firebase
assignments_source: provisa # "claims" or "provisa"
default_role: analyst
default_assignments:
- role_id: analyst
domain_id: "*"
firebase:
project_id: ${env:FIREBASE_PROJECT_ID}
service_account_key: ${env:FIREBASE_SERVICE_ACCOUNT_KEY}
assignments_source: claims קורא שיוכי תפקיד מתביעות (claims) JWT. assignments_source: provisa קורא אותם ממחסן השיוכים של Provisa עצמה. [tool-verified: provisa/core/models.py line 476] (REQ-551)
ניתוב ביצוע¶
ביצוע ישיר — שאילתות RDBMS חד-מקוריות מנותבות לדרייבר הילידי עבור latency מתחת ל-100ms (REQ-027). מקורות דורשים גם רשומת SOURCE_TO_DIALECT וגם רשומת SOURCE_TO_CONNECTOR כדי לתמוך בנתיב זה (REQ-229).
ביצוע מפודרר — שאילתות רב-מקוריות ומקורות ללא דרייבר ישיר מנותבים דרך מנוע הפדרציה (REQ-028). Provisa כוללת מנוע פדרציה מוטמע (embedded); ניתן להצביע על אשכול (cluster) תואם משלכם עבור פריסות בקנה מידה גדול (REQ-226).
סטטיסטיקה — עם הרישום, Provisa מריצה ANALYZE מול כל טבלה שפורסמה כדי להכין את האופטימיזטור מבוסס-עלות (מספרי שורות, שבר null, ערכים ייחודיים, מינימום/מקסימום). כשלים נרשמים ביומן ואינם חוסמים את הרישום (REQ-275).
מקורות גרף וסמנטיקה¶
Neo4j¶
רישום מסד נתוני גרף Neo4j כמקור ניתן לשאילתה. Stewards כותבים שאילתות Cypher המקרינות ערכים סקלריים; Provisa שומרת את התוצאות במטמון וחושפת אותן כטיפוסי GraphQL (REQ-295).
שאילתות Cypher חייבות להשתמש בגישה למאפיין (property accessor) במשפט RETURN (RETURN n.id AS id, n.name AS name) — החזרת אובייקטי node נדחית בזמן הרישום (REQ-296).
# Register via admin API (no YAML config required)
POST /admin/sources/neo4j
{
"source_id": "graph",
"host": "neo4j",
"port": 7474,
"database": "neo4j"
}
# Register a table (preview + validate before persisting)
POST /admin/sources/neo4j/graph/tables
{
"table_name": "person_skills",
"cypher": "MATCH (p:Person)-[:HAS_SKILL]->(s:Skill) RETURN p.name AS name, s.skill AS skill, p.experience AS years",
"ttl": 300
}
נקודת הקצה של תצוגה מקדימה (POST /admin/sources/neo4j/{id}/preview) מחזירה שורות דוגמה וחוסמת רישום אם ה-Cypher מחזיר אובייקטי node (REQ-296).
SPARQL¶
רישום כל triplestore תואם SPARQL 1.1 (Apache Jena Fuseki, Virtuoso, Stardog וכדומה) כמקור ניתן לשאילתה (REQ-297).
השאילתות חייבות להיות שאילתות SELECT. שמות משתנים במשפט ה-SELECT הופכים אוטומטית לשמות עמודות (REQ-297).
# Register via admin API
POST /admin/sources/sparql
{
"source_id": "knowledge-graph",
"endpoint_url": "http://fuseki:3030/ds/sparql",
"default_graph_uri": "http://example.org/graph"
}
# Register a table (executes LIMIT 5 probe to validate and infer columns)
POST /admin/sources/sparql/knowledge-graph/tables
{
"table_name": "product_categories",
"sparql_query": "SELECT ?product ?label ?category WHERE { ?product a :Product ; rdfs:label ?label ; :hasCategory ?category . }",
"ttl": 600
}
שני המחברים משתמשים בצינור המטמון של מקור ה-API — התוצאות מאוחסנות ב-PostgreSQL עם TTL הניתן להגדרה, מה שהופך אותן לזמינות עבור joins מפודררים חוצי-מקורות (REQ-295, REQ-297, REQ-299).
דוגמאות חיבור¶
PostgreSQL¶
- id: sales-pg
type: postgresql
host: postgres
port: 5432
database: provisa
username: provisa
password: ${env:PG_PASSWORD}
Snowflake¶
- id: analytics-sf
type: snowflake
host: org.snowflakecomputing.com
port: 443
database: ANALYTICS
username: svc_provisa
password: ${env:SNOWFLAKE_PASSWORD}
federation_hints:
account: myorg-myaccount
warehouse: COMPUTE_WH
Databricks¶
- id: lakehouse-db
type: databricks
host: my-workspace.azuredatabricks.net
password: ${env:DATABRICKS_TOKEN}
federation_hints:
http_path: /sql/1.0/warehouses/xxxx
MongoDB¶
- id: reviews-mongo
type: mongodb
host: mongodb
port: 27017
database: provisa
username: ""
password: ""
שאילתה חוצת-מקורות¶
{
orders(where: {region: {eq: "us"}}) {
id
amount
customers { # PostgreSQL
name
email
}
productReviews { # MongoDB (federated)
rating
comment
}
}
}
חלקים חד-מקוריים מנותבים ישירות (REQ-027). joins חוצי-מקורות מבצעים פדרציה עם המרת טיפוסים אוטומטית (REQ-028, REQ-552).