
graphql-engine 的 NoSQL Schema Sampling RFC基于 MongoDB 采樣的自動 Schema 生成方案【免費下載鏈接】graphql-engineBlazing fast, instant realtime GraphQL APIs on all your data with fine grained access control, also trigger webhooks on database events.項目地址: https://gitcode.com/gh_mirrors/gr/graphql-engine導讀本文圍繞 Hasura graphql-engine 倉庫中的 RFC 文檔 rfcs/nosql-schema-sampling/readme.md 展開深入解析其提出的基于 NoSQL 采樣自動生成 Schema方案如何利用mongosh Variety Node.js對 MongoDB 集合中的文檔進行采樣分析自動推導出字段形狀與類型分布并生成可回寫數(shù)據(jù)庫的 JSON Schema 驗證規(guī)則從而為 Hasura 的 GraphQL API 提供結(jié)構(gòu)化的 schema 起點。讀完本文你將掌握該 PoC 的完整運行方式、環(huán)境變量與采樣定制方法并理解從文檔采樣到驗證 schema 導出的底層實現(xiàn)鏈路。背景與問題NoSQL 的無模式與 GraphQL 的要結(jié)構(gòu)Hasura 的數(shù)據(jù)庫支持矩陣同時涵蓋 SQL 與 NoSQL 兩大類數(shù)據(jù)源。相比關(guān)系型數(shù)據(jù)庫的強約束NoSQL 數(shù)據(jù)庫如 MongoDB天然缺少預(yù)定義 schema——這帶來了靈活性卻也帶來了一系列工程挑戰(zhàn)RFC 將其歸納為五點固有的非結(jié)構(gòu)化本質(zhì)MongoDB 等 NoSQL 數(shù)據(jù)庫沒有預(yù)定義 schema數(shù)據(jù)管理、定義與演進都變得復(fù)雜GraphQL 需要結(jié)構(gòu)作為護欄GraphQL 圍繞 NoSQL 數(shù)據(jù)源引入的是無固定觀點的護欄un-opinionated guardrails只有在獲得類型安全與結(jié)構(gòu)之后才能提升執(zhí)行性能、提供可預(yù)測的 API 并改善編碼體驗上手易用性差缺少預(yù)定義 schema 使得新用戶無法像接入 SQL 數(shù)據(jù)庫那樣即插即用式地把數(shù)據(jù)源接入 GraphQL導致 onboarding 流程復(fù)雜化校驗 schema 使用率有限項目現(xiàn)有的一個解決方案是使用 MongoDB 自帶的 validation schema但該方案并未被用戶廣泛采用功能對齊訴求讓用戶能夠即時 introspection 并 track MongoDB 中的 Collections 與 Documents可以顯著加速 Hasura 的 onboarding并讓 NoSQL 數(shù)據(jù)庫與 Hasura 支持的其他基于 schema 的數(shù)據(jù)庫達到功能對齊feature parity。提案方案用采樣推導 schema作為 GraphQL schema 的起點針對上述問題RFC 提出的核心方案是構(gòu)建一個基于 NoSQL 采樣技術(shù)的自動 schema 生成工具。其核心思路分三步采樣Sampling對集合collection的全部文檔或子集進行采樣分析Analysis運行分析掌握文檔集合universe of documents中出現(xiàn)的字段形狀shapes與類型分布types生成Generation基于分析結(jié)果生成一個 schema作為 onboarding 起點用于支撐 Hasura 之上的 GraphQL schema。生成的 schema 具備可定制性終端用戶可以根據(jù)需要調(diào)整。RFC 中給出的概念驗證PoC針對 MongoDB 實現(xiàn)并明確指出同一套方法可以推廣到其他 NoSQL 數(shù)據(jù)庫后續(xù)也可以利用 Hasura 的 logical models 直接生成 Hasura 對 schema 的表示該點在 RFC 中以腳注形式標注為后續(xù)工作。開放問題方案落地前仍需回答的設(shè)計決策RFC 坦誠列出了數(shù)個尚未定論的開放問題這些決策直接決定了工具的形態(tài)選擇器selectors需要哪些選擇器來挑選合適的文檔例如在 MongoDB 中可以選擇基于查詢條件query、最大深度max depth、集合百分比percentage of the collection或最大記錄數(shù)max number of records來選擇文檔沖突類型的取舍當同一字段出現(xiàn)多種類型時工具應(yīng)選擇哪種類型例如某字段大部分是int、少量是string應(yīng)取哪種是否需要做成可配置項可選嵌套對象的閾值編寫 schema 時是否應(yīng)提供類似字段必須在 x% 的文檔中出現(xiàn)過must have been found in x % of documents的設(shè)置以過濾僅出現(xiàn)在極少數(shù)記錄中的可選內(nèi)嵌對象工具歸屬該能力應(yīng)實現(xiàn)進核心工具還是保留靈活性作為外部工具集的一部分可復(fù)現(xiàn)性如何以對其他 NoSQL 數(shù)據(jù)庫廠商可復(fù)現(xiàn)的方式實現(xiàn)這些開放問題在后文 PoC 的analyze.sh與 Variety 的配置參數(shù)中其實已經(jīng)出現(xiàn)了初步的答案雛形例如 query/limit/maxDepth讀者可以在實踐中對照思考。概念驗證PoC總體架構(gòu)三件套流水線RFC 提供了一個可實際運行的 MongoDB schema sampler PoC存放在 rfcs/nosql-schema-sampling 目錄下。它由三部分技術(shù)組合而成組件職責mongoshMongoDB 官方 Shell用于連接數(shù)據(jù)庫、枚舉集合、執(zhí)行采樣查詢并驅(qū)動 Variety 腳本VarietyMongoDB schema 分析器倉庫內(nèi)為 schema_sampler/variety.js版本 1.5.1用于對集合文檔做 key/type 統(tǒng)計Node.js運行 validation_exporter.js將 Variety 的分析結(jié)果轉(zhuǎn)換為 MongoDB validation schema整個流水線由 schema_sampler/analyze.sh 編排枚舉集合 → 逐個集合跑 Variety 采樣分析 → 導出 validation schema JSON → 可選地將 schema 寫回 MongoDB。生成的 validation schema 隨后可以被 Hasura 用作 MongoDB 數(shù)據(jù)源之上的 GraphQL schema 生成基礎(chǔ)??焖匍_始docker compose 一鍵運行PoC 使用 docker-compose.yml 定義了兩個服務(wù)mongodbmongo:6鏡像監(jiān)聽宿主機27017端口啟動時通過 sample_data/import.sh 掛載到/docker-entrypoint-initdb.d/自動導入sample_mflix示例數(shù)據(jù)庫內(nèi)置 healthcheck每 5 秒對test庫執(zhí)行db.runCommand(ping).ok最長等待 10 秒、重試 5 次保證采樣器在數(shù)據(jù)庫就緒后才啟動mongodb_samplernode鏡像掛載./schema_sampler與./schema_exports兩個卷command直接執(zhí)行/schema_sampler/analyze.sh并通過depends_on: condition: service_healthy等待 MongoDB 健康。啟動只需一條命令docker compose up啟動后會自動完成加載sample_mflix示例數(shù)據(jù)庫 → healthcheck 等待就緒 → sampler 運行archive.sh應(yīng)為analyze.sh見下文源碼說明完成集合 introspection、Variety 分析、validation schema 轉(zhuǎn)換并回寫 MongoDB。說明RFC 正文提到 sampler 運行/schema_sampler/archive.sh但倉庫實際文件名為 schema_sampler/analyze.sh且 docker-compose 中command也指向analyze.sh——可以推斷正文中的archive.sh為筆誤實際入口以analyze.sh為準。sample_mflix示例數(shù)據(jù)位于 sample_data/sample_mflix包含movies.json約 2.3 萬行、comments.json、theaters.json、users.json、sessions.json及l(fā)oyalty-table.csv。從movies.json的示例文檔可以看到其嵌套結(jié)構(gòu)非常典型——頂層字段包含plot、genres數(shù)組、runtime、cast、awards嵌套對象、imdb嵌套對象含rating/votes/id、tomatoes多層嵌套等正是展示嵌套字段采樣 類型沖突處理的絕佳素材。定制采樣范圍環(huán)境變量一覽mongodb_sampler容器暴露了 5 個環(huán)境變量用于控制采樣行為見 docker-compose.yml環(huán)境變量作用取值示例MONGO_DATABASEMongoDB 連接字符串指向目標數(shù)據(jù)庫mongodb://root:passwordmongodb:27017/sample_mflixMONGO_USERNAMEMongoDB 用戶名rootMONGO_PASSWORDMongoDB 密碼passwordMONGO_SELECT_COLLECTIONS指定要分析采樣的集合逗號分隔空表示全部集合、movies,commentsMONGO_UPDATE_COLLECTIONS是否將生成的 validation schema 自動寫回集合true/false或留空視為 false在 analyze.sh 中可以看到這些變量的實際用法當MONGO_SELECT_COLLECTIONS為空時腳本通過mongosh ... --eval db.getCollectionNames()動態(tài)枚舉全部集合并用tr -d [\[\]\ \n]清理輸出后按逗號拆分否則直接使用環(huán)境變量中給定的集合列表。MONGO_UPDATE_COLLECTIONStrue時腳本會把導出的 validation schema 通過collMod命令回寫為集合的 validator并設(shè)置validationAction: warn——即僅對不符合 schema 的寫入發(fā)出警告而不拒絕屬于溫和的漸進式約束。深度定制采樣方式改造 analyze.sh 中的 mongosh 查詢?nèi)绻阈枰淖儾蓸幽男┪臋nRFC 指出可以編輯 schema_sampler/analyze.sh 文件。第 29 行是數(shù)據(jù)采樣的核心命令mongosh ${MONGO_DATABASE} --quiet --eval var collection ${collection//\/}, outputFormatjson --username ${MONGO_USERNAME} --password ${MONGO_PASSWORD} --authenticationDatabaseadmin /schema_sampler/variety.js /schema_exports/analysis/${collection//\/}.json這條命令通過--eval向 Variety 注入collection與outputFormatjson兩個全局變量將 variety.js 作為 mongosh 腳本執(zhí)行并把 JSON 形式的分析結(jié)果寫入/schema_exports/analysis/collection.json。定制采樣方式的方法是修改--eval中的參數(shù)RFC 給出的兩個例子添加find()例如var query { version: 2 }只對使用某個 schema 版本的記錄采樣添加limit()例如只返回前 5000 條記錄。這兩個參數(shù)對應(yīng) Variety 內(nèi)置的配置項。在 variety.js 的readConfig中可以看到 Variety 支持的完整配置清單除collection、query、limit外還包括maxDepth默認 99嵌套對象的遞歸分析深度上限sort默認{_id: -1}采樣前的排序方式影響limit截取的樣本outputFormat默認asciiPoC 中設(shè)為json結(jié)果輸出格式persistResults/resultsDatabase/resultsCollection是否將結(jié)果持久化到 MongoDB 及目標庫表arrayEscape默認XX數(shù)組元素在 key 中的轉(zhuǎn)義標記如genres.XX0XXexcludeSubkeys需要排除分析的子 key 列表lastValue是否記錄每個 key 的最后觀測值。這些參數(shù)為按查詢過濾、按數(shù)量截斷、按深度限制等采樣策略提供了底層支撐也正是 RFC 開放問題中選擇器的一種具體化實現(xiàn)。原理縱深從 Variety 分析結(jié)果到 $jsonSchemaVariety 的分析過程Varietyschema_sampler/variety.js的核心邏輯分四步序列化serializeDoc將每個文檔遞歸展平為parentKey.key形式的一維 key 映射數(shù)組元素以arrayEscape 索引 arrayEscape默認XX0XX的形式命名如cast.XX0XX同時受maxDepth限制遞歸深度類型判定varietyTypeOf對每個值判定類型輸出包括String、Number、NumberLong、Boolean、Date、ObjectId、BinData-subtype、Array、Object、null等合并統(tǒng)計mergeDocument跨文檔累積每個 key 出現(xiàn)的類型計數(shù)types與出現(xiàn)總次數(shù)totalOccurrences結(jié)果轉(zhuǎn)換convertResults生成形如{ _id: { key }, value: { types }, totalOccurrences, percentContaining }的條目數(shù)組其中percentContaining表示該字段在多少百分比的文檔中出現(xiàn)——這正是 RFC 開放問題中字段出現(xiàn)頻率閾值的原始數(shù)據(jù)來源。validation_exporter.js 的轉(zhuǎn)換邏輯validation_exporter.js 讀取/schema_exports/analysis/collection.json將其轉(zhuǎn)換為 MongoDB$jsonSchema格式的 validation schema轉(zhuǎn)換規(guī)則值得逐條解讀按.拆分 Variety 的扁平 key還原嵌套結(jié)構(gòu)逐層構(gòu)建properties樹類型沖突處理若某字段檢測到多種類型typeKeys.length 1一律保守地降級為string代碼第 19-23 行特殊類型映射objectid轉(zhuǎn)為objectIdBSON 類型object類型會繼續(xù)作為嵌套層展開其子屬性結(jié)果寫入/schema_exports/validation_schema/collection.json頂層包裹為{ $jsonSchema: { bsonType: object, required: [], properties: {...} } }。一個值得注意的細節(jié)轉(zhuǎn)換器默認將出現(xiàn)多類型的字段歸為string這是一種保守的最小公分母策略——寧可放寬類型也不讓 schema 過早拒絕數(shù)據(jù)。這恰好對應(yīng) RFC 開放問題 2 中沖突類型如何取舍的討論PoC 選擇了最簡單直接的默認策略而是否可配置則留待后續(xù)迭代。從 validation schema 到 Hasura GraphQL schemaRFC 明確指出回寫后的 MongoDB validation schema 可以成為 Hasura 生成 GraphQL schema 的依據(jù)生成的 schema 先寫回 MongoDBcollMod validator再由 Hasura 基于該數(shù)據(jù)源生成 GraphQL schema同時 RFC 標注了后續(xù)方向——利用 Hasura 的 logical models 直接生成 Hasura 表示的 schema從而讓整個采樣 → 分析 → 生成流水線與 Hasura 的類型系統(tǒng)無縫銜接。驗證與調(diào)試查看容器日志運行docker logs mongodb_sampling可以看到采樣容器內(nèi)的執(zhí)行過程——analyze.sh中大量使用 emoji 標注步驟如安裝依賴、?枚舉集合、分析、轉(zhuǎn)換、回寫方便快速定位流水線卡在哪一步檢查中間產(chǎn)物./schema_exports卷包含兩個子目錄schema_exports/analysis/Variety 的原始分析結(jié)果每個集合一個 JSONschema_exports/validation_schema/轉(zhuǎn)換后的$jsonSchema驗證 schema每個集合一個 JSON。你可以直接查看這些 JSON 文件驗證采樣 → 分析 → 導出每個環(huán)節(jié)的輸出是否符合預(yù)期。局限與未來方向從源碼結(jié)構(gòu)看該 PoC 有幾個明顯的邊界讀者在參考時應(yīng)留意類型沖突策略硬編碼多類型字段統(tǒng)一降級為string的邏輯寫死在 validation_exporter.js 中尚不支持配置化依賴外部工具Variety 是 MIT 許可的第三方分析器schema_sampler/variety.js 文件頭注釋注明版權(quán)與許可證mongosh 則在 analyze.sh 中通過 apt 動態(tài)安裝尚未進入 Hasura 核心RFC 開放問題 4 中核心工具 vs 外部工具集的歸屬問題尚未定論當前 PoC 以獨立 docker-compose 形式存在并未合入 graphql-engine 主服務(wù)。RFC 中展望的未來方向包括將同一采樣方法復(fù)用于其他 NoSQL 數(shù)據(jù)庫廠商、通過 logical models 直接生成 Hasura schema 表示以及在類型沖突、字段頻率閾值等方面引入可配置策略。如果你正在為 NoSQL 數(shù)據(jù)源設(shè)計自動 schema 推導工具這個 PoC 的采樣 → 分析 → 生成 → 回寫流水線是一份可以直接借鑒的完整參考實現(xiàn)?!久赓M下載鏈接】graphql-engineBlazing fast, instant realtime GraphQL APIs on all your data with fine grained access control, also trigger webhooks on database events.項目地址: https://gitcode.com/gh_mirrors/gr/graphql-engine創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考