Skip to content

การออกแบบโมเดลข้อมูล NoSQL อธิบาย

รูปแบบการสร้างโมเดลข้อมูลสำหรับ document, key-value, wide-column, graph และ vector store — จะเลือก embed, reference, denormalize หรือ bucket เมื่อไหร่

ฐานข้อมูล NoSQL แลก schema ที่ตายตัวและ join กับความสามารถในการขยายแนวนอน แต่ละตระกูลจัดการความสัมพันธ์ของข้อมูลด้วยวิธีของตัวเอง ดังนั้น access pattern ต่างหากที่กำหนดโครงสร้าง ไม่ใช่ normal form

ตารางอ้างอิง · 28 รายการ
28 of 28 rows
เอกสาร (Document)
sub-document ที่ซ้อนกันอยู่ภายในเอกสารแม่เดียว แทนที่จะแยกเป็นตารางต่างหากความสัมพันธ์แบบ one-to-few ที่ต้องอ่านพร้อมกัน เช่น ออเดอร์กับรายการสินค้า หรือผู้ใช้ที่มีสามที่อยู่
เก็บแค่ id ของฝั่งตรงข้าม ไม่เก็บข้อมูลจริง แล้วดึงมาด้วยการอ่านครั้งที่สองหรือใช้ $lookupเอนทิตีย่อยที่ใหญ่ ถูกใช้ร่วมกัน หรือถูกอัปเดตแยกจากกัน เช่น ความสัมพันธ์ many-to-many ข้ามคอลเลกชัน
เอกสารแม่ฝัง array สั้น ๆ ของลูกไว้ ทั้งชุดจึงพอดีและโหลดมาเป็นเอกสารเดียวเบอร์โทรหรือ preference ไม่กี่รายการในโปรไฟล์ อ่านครั้งเดียวได้ทั้งแม่และลูก
ลูกอยู่ในคอลเลกชันของตัวเอง แต่ละตัวมี parent id หรือไม่ก็ฝั่งแม่เก็บ array ของ id ที่มีขอบเขตจำกัดชุดข้อมูลที่ใหญ่หรือเป็นอิสระเกินกว่าจะฝัง ค้นหาลูกด้วย parent id
ลูกเป็นผู้เก็บ parent id ฝั่งแม่ไม่เก็บรายชื่อลูกเลยเพราะชุดข้อมูลไม่มีขอบเขตบนevent, log หรือ vote ที่ผูกกับ host หรือผู้ใช้ กรองลูกด้วย parent id แล้วแบ่งหน้า
เอกสารของหลายชนิดเอนทิตีใช้คอลเลกชันเดียวกัน แยกกันด้วยฟิลด์ typecomment หรือ notification ที่เกาะกับแม่หลายชนิด แต่ค้นหาด้วยวิธีเดียว
แยกเอนทิตีสุดโต่งไม่กี่ตัวออกจากรูปทรงปกติ เพื่อไม่ให้ขนาดหรือปริมาณ traffic ของมันบิดเบือนส่วนที่เหลือบัญชีคนดังที่รายชื่อผู้ติดตามหรือตัวนับจะโตเกินขนาดเอกสารปกติ
แต่ละรีวิชันคือเอกสารใหม่ที่มี id เดิมและเลขเวอร์ชันที่เพิ่มขึ้น คิวรีเลือกเอาตัวล่าสุดaudit trail และประวัติการแก้ไขที่ยังต้องค้นย้อนรีวิชันเก่าได้
ค่าที่คำนวณได้ถูกคำนวณตอนเขียนแล้วเก็บไว้ข้างข้อมูลที่มันสรุปยอดรวม คะแนน rating และ top-N ที่ไม่อยากวิ่ง aggregation ทุกครั้งที่อ่าน
Key-value และ wide-column
คำศัพท์ออกแบบของ DynamoDB: รวมหลายชนิดเอนทิตีลงตารางเดียวโดยใช้ partition key และ sort key แบบ overloadedดึง item หลากหลายชนิดมาในคิวรีเดียวโดยไม่ต้อง join
แอตทริบิวต์คีย์เดียวใช้กับหลายชนิดเอนทิตี กำกับด้วย prefix อย่าง USER# หรือ ORDER#งานออกแบบ single-table จับกลุ่ม item ที่เกี่ยวข้องไว้ใน partition เดียวแล้วดึงมาในคิวรีเดียว
partition key กระจายแถวข้ามโหนด ส่วน sort key จัดลำดับภายในแต่ละ partitionCassandra และ DynamoDB งาน range scan, log ที่ต้องเรียงตามลำดับ, composite key แบบลำดับชั้น
เอาหลายแอตทริบิวต์มาต่อกันเป็น sort key เดียวที่มีตัวคั่น — country#region#city — เพื่อให้ prefix match เดินลงตามลำดับชั้นโครงสร้างลำดับชั้นและตัวกรองหลายมิติ range query เดียวที่เรียงแล้วแทนการค้น index หลายรอบ
จับกลุ่ม event เข้าหน้าต่างเวลาคงที่ — ชั่วโมง วัน เดือน — ใน partition หรือตารางเฉพาะmetrics, log และ telemetry จาก IoT จำกัดขนาด partition และทิ้งข้อมูลเย็นตามอายุ
ทำสำเนาฟิลด์ที่อ่านบ่อยไว้ในหลาย record เพื่อให้คิวรีไม่ต้องวิ่งตาม lookup รอบที่สองงานที่อ่านหนักกว่าเขียนมาก ยอมรับ eventual consistency ได้และพื้นที่จัดเก็บถูก
secondary index ที่สร้างบนแอตทริบิวต์ที่มีเฉพาะบาง item ตัวที่ไม่มีก็ไม่เข้า indexทางเข้าถึงแบบสำรอง หา subset แบบ sparse — ออเดอร์ที่ยังเปิด, ของที่ยังไม่ส่ง — โดยไม่ต้อง scan ทั้งตาราง
เขียนคิวรีที่ต้องการลงไปก่อนเป็นตัวตั้ง โครงร่างตารางค่อย derive มาจากคิวรี ไม่ใช่จากเอนทิตีหรือ normal formงานออกแบบ schema ของ Cassandra และ DynamoDB ตารางเดียวต่อกลุ่มคิวรี โมเดลข้อมูลลอกคำถามไปเลย
คิวรีต้องกระทบหลาย partition หรือหลายโหนดพร้อมกันเพราะไม่มีคีย์ไหนตรงกับคำถามเป็นกลิ่นที่ต้องออกแบบให้หายไป ไม่ใช่เป้าหมาย เปลี่ยนคีย์ของตารางให้คิวรีที่พบบ่อยลง partition เดียว
สำเนาถูกผลักไปยัง view ของผู้อ่านแต่ละคนตอนเขียน หรือไม่ก็รวบรวมแล้ว merge ตอนอ่านfeed และ timeline fan-out ตอนเขียนสำหรับผู้ชมกลุ่มเล็ก ตอนอ่านสำหรับกลุ่มที่ใหญ่มาก
ผลลัพธ์คิวรีที่คำนวณไว้ล่วงหน้าแล้วเก็บเป็นตารางของตัวเอง ดูแลให้ทันสมัยตามตารางหลักรูปทรงการอ่านแบบอื่นบนเส้นทางเขียนเดียว ตอบคิวรีที่ตารางหลักตอบไม่ได้
กราฟ (Graph)
แต่ละ edge คือแถวหรือ tuple ที่ชี้จากโหนดต้นทางไปยังโหนดปลายทางgraph และ property store งานค้นแบบ friend-of-friend, routing, ระบบแนะนำ
แต่ละความสัมพันธ์เป็นเอกสารในคอลเลกชันของตัวเอง มี id ฝั่ง from กับ to พร้อมแอตทริบิวต์ของลิงก์กราฟใน document store แอตทริบิวต์อยู่บนลิงก์เอง — rating, role, timestamp
ทุกโหนดเก็บตัวนับฝั่งซ้ายและขวาจากการเดินแบบ depth-first ทั้ง subtree อยู่ในช่วงของแม่ต้นไม้ที่อ่านหนัก คิวรี BETWEEN เดียวได้ทั้ง subtree ส่วนการ insert ต้องเรนัมเบอร์การเดินใหม่
ตารางเฉพาะที่บันทึกคู่บรรพบุรุษ-ลูกหลานทุกคู่ รวมถึงโหนดตัวมันเองที่ depth เป็นศูนย์คิวรีทั้งกิ่งที่ความลึกเท่าไหร่ก็ได้ join ง่าย แต่จ่ายด้วยพื้นที่จัดเก็บและการดูแลรักษา
property graph แปะแอตทริบิวต์แบบ key-value บนโหนดและ edge ส่วน RDF เขียนทุกอย่างเป็น triple แบบ subject-predicate-objectproperty graph สำหรับ traversal ที่ซับซ้อน (Neo4j) RDF สำหรับ linked open data และการแลกเปลี่ยน ontology
เวกเตอร์ (Vector)
array ของ float มิติสูงวางอยู่ข้าง metadata โดยมี index แบบ ANN คอยหาเพื่อนบ้านที่ใกล้ที่สุดsemantic search, การดึงข้อมูล RAG, ระบบแนะนำ และการหาความคล้ายบนเนื้อหาที่ไม่มีโครงสร้าง
เอกสารต้นทางถูกตัด — ตามขนาด ตามส่วนซ้อนทับ หรือตามโครงสร้าง — ก่อนที่ชิ้นแต่ละชิ้นจะถูก embed แยกจากกันคุณภาพการดึงข้อมูลของ RAG ขนาด chunk แลก precision กับ recall ส่วน overlap ปกป้องประโยคที่ถูกตัด
ความคล้ายแบบ dense vector ทำงานคู่กับการจับคู่คีย์เวิร์ด แล้วเอาอันดับสองชุดมา fuse เป็นผลลัพธ์เดียวคิวรีที่ต้องการทั้งคำตรงตัวและความหมายพร้อมกัน พร้อมตัวกรอง metadata ซ้อนขึ้นไป