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