วิวัฒนาการของโครงสร้างข้อมูลและความเข้ากันได้ย้อนหลัง
จัดการการเปลี่ยนแปลงโครงสร้างข้อมูลที่ทำให้ระบบเดิมใช้งานไม่ได้ในกระบวนการดึงข้อมูลระยะยาว ด้วยการกำหนดเวอร์ชันโครงสร้างข้อมูล ย้ายข้อมูลที่ดึงไว้ในอดีต และตรวจสอบแบบขนานระหว่างการเปลี่ยนผ่าน
วิวัฒนาการของโครงสร้างข้อมูลและความเข้ากันได้ย้อนหลัง เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Engineering Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดสคีมาจึงเปลี่ยนแปลงไปตามเวลา
สคีมาสำหรับการดึงข้อมูลไม่ได้หยุดนิ่ง ข้อกำหนดทางธุรกิจเปลี่ยนแปลงไป มีประเภทเอกสารใหม่เกิดขึ้น และคุณอาจค้นพบช่องข้อมูลที่ควรเก็บตั้งแต่แรก การเปลี่ยนสคีมาในสายงานที่ใช้งานจริงทำให้เกิด ปัญหาความเข้ากันได้แบบย้อนหลัง: ระเบียนที่ดึงข้อมูลไปแล้วใช้สคีมาเก่า ส่วนระเบียนใหม่ใช้สคีมาใหม่ การจัดการการเปลี่ยนผ่านนี้อย่างปลอดภัยคือหัวใจของวิวัฒนาการสคีมา
กำหนดเวอร์ชันให้สคีมา
กำหนด หมายเลขเวอร์ชัน ให้สคีมาแต่ละรายการและจัดเก็บไว้คู่กับระเบียนที่ดึงข้อมูลทุกระเบียน เมื่อเปลี่ยนสคีมา ให้เพิ่มหมายเลขเวอร์ชัน วิธีนี้ช่วยให้คุณค้นหาระเบียนตามเวอร์ชันสคีมา เรียกใช้การย้ายข้อมูลกับระเบียนเก่า และดูแลตรรกะการตรวจสอบแยกสำหรับแต่ละเวอร์ชันได้ ช่องข้อความแบบง่าย schema_version ในโมเดลผลลัพธ์ทุกรายการก็เพียงพอ
from pydantic import BaseModel
from typing import Literal
class InvoiceV1(BaseModel):
schema_version: Literal['1.0'] = '1.0'
vendor: str
total_amount: float
class InvoiceV2(BaseModel):
schema_version: Literal['2.0'] = '2.0'
vendor: str
vendor_tax_id: str | None = None # new field
total_amount: float
currency: str = 'USD' # new field with defaultการเปลี่ยนแปลงแบบเพิ่มข้อมูลกับการเปลี่ยนแปลงที่ทำให้ใช้ไม่ได้
การเปลี่ยนแปลงแบบเพิ่มข้อมูลปลอดภัย: การเพิ่มช่องข้อมูล Optional หรือช่องข้อมูลที่มีค่าเริ่มต้นจะไม่ทำให้โค้ดดึงข้อมูลเดิมหรือระเบียนเดิมใช้ไม่ได้ การเปลี่ยนแปลงที่ทำให้ใช้ไม่ได้มีความเสี่ยง: การเปลี่ยนชื่อช่องข้อมูล การเปลี่ยนชนิดจากสตริงเป็นจำนวนเต็ม หรือการลบช่องข้อมูลจะทำให้ผู้ใช้ข้อมูลปลายทางทำงานไม่ได้ ควรเลือกการเปลี่ยนแปลงแบบเพิ่มข้อมูลเสมอ หากหลีกเลี่ยงการเปลี่ยนแปลงที่ทำให้ใช้ไม่ได้ไม่ได้ ให้สร้างสคีมาเวอร์ชันหลักใหม่และย้ายข้อมูลอย่างมีการควบคุม
# Safe: additive change - add optional field
class ProductV2(BaseModel):
name: str
price: float
sku: str | None = None # NEW optional field - backward safe
category: str = 'general' # NEW with default - backward safe
# Risky: breaking change - rename or retype
# class ProductV2(BaseModel):
# product_name: str # RENAMED from name - breaks consumers
# price_cents: int # RETYPED from float - breaks dataจัดเก็บเวอร์ชันสคีมาในฐานข้อมูล
ใส่เวอร์ชันสคีมาไว้ในตารางผลลัพธ์การดึงข้อมูล เพื่อให้คุณทราบเสมอว่าแต่ละระเบียนสร้างจากเวอร์ชันใด คอลัมน์ jsonb ที่เก็บข้อมูลที่ดึงมาทั้งหมดร่วมกับคอลัมน์ข้อความ schema_version เป็นรูปแบบที่ใช้กันทั่วไป วิธีนี้ช่วยให้คุณเขียนคำค้นที่รู้จักเวอร์ชัน และย้ายระเบียนเก่าเฉพาะส่วนในช่วงที่มีการใช้งานต่ำได้
-- PostgreSQL table design
CREATE TABLE extractions (
doc_id TEXT PRIMARY KEY,
schema_version TEXT NOT NULL,
extracted_data JSONB NOT NULL,
extracted_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_schema_version ON extractions(schema_version);
-- Query old records needing migration
SELECT doc_id, extracted_data
FROM extractions
WHERE schema_version = '1.0'
LIMIT 1000;เขียนสคริปต์ย้ายข้อมูล
เขียน สคริปต์ย้ายข้อมูล สำหรับการเปลี่ยนผ่านสคีมาแต่ละเวอร์ชัน โดยอ่านระเบียนเก่า แปลงเป็นรูปแบบใหม่ แล้วเขียนกลับพร้อมเวอร์ชันใหม่ เรียกใช้การย้ายข้อมูลเป็นชุดเล็ก ๆ พร้อมธุรกรรม เพื่อไม่ให้ความล้มเหลวทำให้ฐานข้อมูลอยู่ในสถานะย้ายข้อมูลเพียงครึ่งเดียว เก็บสคีมาเก่าไว้เสมอจนกว่าจะตรวจสอบว่าการย้ายข้อมูลเสร็จสมบูรณ์
import asyncpg
import json
async def migrate_v1_to_v2(pool, batch_size=100):
async with pool.acquire() as conn:
rows = await conn.fetch(
'SELECT doc_id, extracted_data FROM extractions WHERE schema_version=$1 LIMIT $2',
'1.0', batch_size
)
for row in rows:
old = row['extracted_data']
new_data = {
'schema_version': '2.0',
'vendor': old['vendor'],
'vendor_tax_id': None, # unknown for old records
'total_amount': old['total_amount'],
'currency': 'USD' # assume USD for old records
}
await conn.execute(
'UPDATE extractions SET extracted_data=$1, schema_version=$2 WHERE doc_id=$3',
json.dumps(new_data), '2.0', row['doc_id']
)ตรวจสอบแบบขนานระหว่างการเปลี่ยนผ่าน
ระหว่างการย้ายสคีมา ให้ทำ การตรวจสอบแบบขนาน: ดึงข้อมูลด้วยสคีมาเก่าและใหม่พร้อมกันจากเอกสารขาเข้าตัวอย่าง เปรียบเทียบผลลัพธ์เพื่อยืนยันว่าสคีมาใหม่เก็บข้อมูลได้ครบถ้วนเท่ากับสคีมาเก่าและยังมีช่องข้อมูลใหม่เพิ่มขึ้น ยกเลิกสคีมาเก่าก็ต่อเมื่อการตรวจสอบแบบขนานแสดงความสอดคล้องที่คงที่จากกลุ่มตัวอย่างซึ่งมีนัยสำคัญทางสถิติ
async def parallel_validate(text: str) -> dict:
v1_result, v2_result = await asyncio.gather(
extract_with_schema(text, InvoiceV1),
extract_with_schema(text, InvoiceV2)
)
discrepancy = (
v1_result.vendor != v2_result.vendor or
abs(v1_result.total_amount - v2_result.total_amount) > 0.01
)
if discrepancy:
log_discrepancy(text, v1_result, v2_result)
return {'v1': v1_result, 'v2': v2_result, 'discrepancy': discrepancy}ใช้แฟล็กฟีเจอร์เพื่อทยอยเปิดใช้สคีมา
ใช้ แฟล็กฟีเจอร์ควบคุมเวลาที่สายงานจะเปลี่ยนจากสคีมาเก่าไปใช้สคีมาใหม่ วิธีนี้ช่วยให้คุณทยอยเปิดใช้สคีมาใหม่กับปริมาณการใช้งานบางส่วน ตรวจสอบอัตราข้อผิดพลาด และย้อนกลับได้ทันทีหากเกิดปัญหา โดยไม่ต้องนำโค้ดขึ้นระบบใหม่ บริการแฟล็กฟีเจอร์อย่าง LaunchDarkly หรือแถวข้อมูลธรรมดาในฐานข้อมูลก็ใช้ได้ทั้งคู่
import os
def get_active_schema():
version = os.environ.get('EXTRACTION_SCHEMA_VERSION', '1.0')
schemas = {
'1.0': InvoiceV1,
'2.0': InvoiceV2,
}
return schemas.get(version, InvoiceV1)
async def extract_document(text: str):
SchemaClass = get_active_schema()
return await extract_with_schema(text, SchemaClass)ความเข้ากันได้ของผู้ใช้ข้อมูลด้วยชนิดยูเนียน
ผู้ใช้ข้อมูลปลายทางที่อ่านข้อมูลที่ดึงมาต้องรองรับสคีมาหลายเวอร์ชันได้อย่างเหมาะสม ใช้ ยูเนียนที่มีตัวแยกประเภทในโค้ดของผู้ใช้ข้อมูล เพื่อเลือกตรรกะการแยกวิเคราะห์ที่ถูกต้องตามช่อง schema_version วิธีนี้ทนทานกว่าการเขียนเงื่อนไข if-else ต่อกัน และขยายได้ง่ายกว่าเมื่อมีเวอร์ชัน 3
from pydantic import BaseModel
from typing import Union, Annotated
from typing import Literal
def parse_extraction(raw: dict) -> Union[InvoiceV1, InvoiceV2]:
version = raw.get('schema_version', '1.0')
if version == '1.0':
return InvoiceV1(**raw)
elif version == '2.0':
return InvoiceV2(**raw)
else:
raise ValueError(f'Unknown schema version: {version}')ทดสอบการเปลี่ยนแปลงสคีมาก่อนนำขึ้นระบบ
ก่อนนำสคีมาใหม่ขึ้นระบบ ให้เรียกใช้กับ ชุดทดสอบการถดถอยทั้งหมด ซึ่งเป็นชุดเอกสารตัวแทนที่คัดสรรไว้และมีผลลัพธ์ที่คาดหมายทราบอยู่แล้ว เปรียบเทียบคะแนน F1 ของแต่ละช่องข้อมูลระหว่างสคีมาเก่าและใหม่ หาก F1 ของช่องใดลดลง แสดงว่าคำอธิบายสคีมาใหม่ทำให้โมเดลสับสน ให้แก้คำอธิบายช่องข้อมูลก่อนนำไปใช้งาน
def eval_schema_on_test_set(test_cases: list, SchemaClass) -> dict:
field_f1 = {}
for case in test_cases:
result = extract_with_schema(case['text'], SchemaClass)
for field in case['expected']:
expected = case['expected'][field]
actual = getattr(result, field, None)
# Update precision/recall counters
update_metrics(field_f1, field, expected, actual)
return {k: compute_f1(v) for k, v in field_f1.items()}จัดการการเลิกใช้สคีมา
เมื่อไม่มีการใช้สคีมาเวอร์ชันหนึ่งกับการดึงข้อมูลใหม่แล้ว คุณสามารถประกาศเลิกใช้ได้ การเลิกใช้หมายถึง หยุดรับระเบียนใหม่ในเวอร์ชันนั้น ยังคงอ่านระเบียนเก่าได้ และกำหนดวันที่ยุติการใช้งานเมื่อระเบียนเก่าจะถูกย้ายหรือเก็บถาวร บันทึกการเลิกใช้ไว้ในบันทึกการเปลี่ยนแปลง เพื่อให้ผู้ใช้ข้อมูลทั้งหมดทราบว่าต้องอัปเกรดโค้ดแยกวิเคราะห์
DEPRECATED_VERSIONS = {'1.0'}
SUNSET_DATE = '2026-09-01'
def warn_if_deprecated(version: str):
if version in DEPRECATED_VERSIONS:
import warnings
warnings.warn(
f'Schema version {version} is deprecated. '
f'It will be removed after {SUNSET_DATE}. '
'Migrate consumers to version 2.0.',
DeprecationWarning,
stacklevel=2
)บันทึกการเปลี่ยนแปลงและการสื่อสาร
การเปลี่ยนสคีมาทุกครั้งต้องมี รายการในบันทึกการเปลี่ยนแปลง ซึ่งอธิบายสิ่งที่เปลี่ยน เหตุผล คำแนะนำในการย้ายข้อมูล และผลกระทบที่คาดไว้ แชร์รายการเหล่านี้กับทุกทีมที่ใช้ข้อมูลที่ดึงมาก่อนนำการเปลี่ยนแปลงขึ้นระบบ เหตุการณ์ย้ายสคีมาที่ล้มเหลวหลายครั้งไม่ได้เกิดจากปัญหาทางเทคนิค แต่เกิดจากผู้ใช้ข้อมูลที่ไม่ทราบว่ากำลังจะมีการเปลี่ยนแปลง
# CHANGELOG.md entry format:
# ## Schema v2.0 (2026-07-01)
# ### Changes
# - ADDED: vendor_tax_id (Optional[str]) - VAT/EIN extracted from header
# - ADDED: currency (str, default='USD') - detected from symbol/code
# ### Migration
# Run: python scripts/migrate_v1_to_v2.py --batch-size=500
# ### Consumers
# - billing-service: update parse_extraction() to handle v2
# - audit-service: query now supports currency filterตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจของคุณเกี่ยวกับวิวัฒนาการสคีมาและความเข้ากันได้แบบย้อนหลังในสายงานการดึงข้อมูล
ทบทวนบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า การกำหนดเวอร์ชันสคีมาจะจัดเก็บตัวระบุเวอร์ชันไว้คู่กับระเบียนที่ดึงข้อมูลทุกระเบียน เพื่อให้คุณย้ายข้อมูลเฉพาะส่วนได้ การเปลี่ยนแปลงแบบเพิ่มข้อมูลปลอดภัย ขณะที่การเปลี่ยนชื่อหรือเปลี่ยนชนิดของช่องข้อมูลต้องย้ายข้อมูลอย่างระมัดระวัง และ การตรวจสอบแบบขนานช่วยให้คุณยืนยันสคีมาใหม่ก่อนยกเลิกสคีมาเก่า บทถัดไป เราจะวัดความหน่วงของ LLM ด้วยตัวชี้วัด TTFT และ TPOT
เรียนรู้ Python ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “วิวัฒนาการของโครงสร้างข้อมูลและความเข้ากันได้ย้อนหลัง” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “วิวัฒนาการของโครงสร้างข้อมูลและความเข้ากันได้ย้อนหลัง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “วิวัฒนาการของโครงสร้างข้อมูลและความเข้ากันได้ย้อนหลัง”
จัดการการเปลี่ยนแปลงโครงสร้างข้อมูลที่ทำให้ระบบเดิมใช้งานไม่ได้ในกระบวนการดึงข้อมูลระยะยาว ด้วยการกำหนดเวอร์ชันโครงสร้างข้อมูล ย้ายข้อมูลที่ดึงไว้ในอดีต และตรวจสอบแบบขนานระหว่างการเปลี่ยนผ่าน คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “วิวัฒนาการของโครงสร้างข้อมูลและความเข้ากันได้ย้อนหลัง” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม
ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- Instructor: การดึงข้อมูลแบบมีชนิดด้วย Pydantic
- การจัดการข้อมูลบางส่วนและข้อมูลที่ขาดหาย
- การประมวลผลเป็นชุดด้วยอะซิงโครนัสและคิว
- วิวัฒนาการของโครงสร้างข้อมูลและความเข้ากันได้ย้อนหลัง