SiamCafe.net Blog
Technology

Parquet Format Career Development IT

parquet format career development it
Parquet Format Career Development IT | SiamCafe Blog
2026-03-16· อ. บอม — SiamCafe.net· 1,803 คำ

Parquet Format Career Development IT คืออะไร

Apache Parquet เป็น columnar storage format ที่ออกแบบสำหรับ big data analytics มีประสิทธิภาพสูงทั้งด้าน compression และ query speed เป็นมาตรฐานใน data engineering ecosystem ใช้ร่วมกับ Spark, Pandas, DuckDB, BigQuery, Snowflake และ tools อื่นๆ ความรู้เรื่อง Parquet เป็นทักษะสำคัญสำหรับ IT career development โดยเฉพาะสาย Data Engineer, Data Analyst และ ML Engineer บทความนี้อธิบาย Parquet format ลึกซึ้ง พร้อมแนวทางพัฒนาอาชีพ IT

Parquet Format Fundamentals

# parquet_basics.py — Parquet format fundamentals
import json

class ParquetBasics:
    FEATURES = {
        "columnar": {
            "name": "Columnar Storage",
            "description": "เก็บข้อมูลเป็น column ไม่ใช่ row — อ่านเฉพาะ columns ที่ต้องการ",
            "benefit": "Query เร็วกว่า CSV 10-100x สำหรับ analytical queries",
        },
        "compression": {
            "name": "Efficient Compression",
            "description": "Compress ได้ดีมาก — column เดียวกันมี data type เหมือนกัน",
            "benefit": "ไฟล์เล็กกว่า CSV 2-10x (Snappy, Zstd, Gzip)",
        },
        "schema": {
            "name": "Schema Evolution",
            "description": "เก็บ schema ในไฟล์ — เพิ่ม/ลบ columns ได้โดยไม่ break",
            "benefit": "ไม่ต้องจัดการ schema แยก — self-describing format",
        },
        "predicate_pushdown": {
            "name": "Predicate Pushdown",
            "description": "กรองข้อมูลระดับ storage — ไม่ต้องอ่านทั้งไฟล์",
            "benefit": "ลด I/O มหาศาล — อ่านเฉพาะ row groups ที่ match",
        },
        "encoding": {
            "name": "Advanced Encoding",
            "description": "Dictionary, RLE, Delta, Bit Packing — encode ตาม data type",
            "benefit": "ลดขนาดเพิ่มเติมหลัง compression",
        },
    }

    VS_CSV = {
        "read_speed": {"csv": "ช้า (parse text ทุก row)", "parquet": "เร็วมาก (binary, columnar)"},
        "file_size": {"csv": "ใหญ่ (plain text)", "parquet": "เล็ก 2-10x (compressed)"},
        "schema": {"csv": "ไม่มี (ต้อง infer)", "parquet": "มีในไฟล์ (self-describing)"},
        "column_pruning": {"csv": "ไม่ได้ (อ่านทุก column)", "parquet": "ได้ (อ่านเฉพาะที่ต้องการ)"},
        "human_readable": {"csv": "ใช่", "parquet": "ไม่ (binary format)"},
    }

    def show_features(self):
        print("=== Parquet Features ===\n")
        for key, feat in self.FEATURES.items():
            print(f"[{feat['name']}]")
            print(f"  {feat['description']}")
            print(f"  Benefit: {feat['benefit']}")
            print()

    def show_vs_csv(self):
        print("=== Parquet vs CSV ===")
        print(f"  {'Feature':<20} {'CSV':<30} {'Parquet'}")
        for feat, vals in self.VS_CSV.items():
            print(f"  {feat:<20} {vals['csv']:<30} {vals['parquet']}")

basics = ParquetBasics()
basics.show_features()
basics.show_vs_csv()

Python Parquet Operations

# parquet_ops.py — Python Parquet operations
import json

class ParquetOperations:
    CODE = """
# parquet_tools.py — Work with Parquet files in Python
import pyarrow as pa
import pyarrow.parquet as pq
import pandas as pd
from pathlib import Path

class ParquetManager:
    def __init__(self, data_dir="./data"):
        self.data_dir = Path(data_dir)
        self.data_dir.mkdir(exist_ok=True)
    
    def csv_to_parquet(self, csv_path, parquet_path=None, compression='snappy'):
        '''Convert CSV to Parquet'''
        df = pd.read_csv(csv_path)
        
        if parquet_path is None:
            parquet_path = csv_path.replace('.csv', '.parquet')
        
        df.to_parquet(parquet_path, compression=compression, index=False)
        
        csv_size = Path(csv_path).stat().st_size / 1e6
        parquet_size = Path(parquet_path).stat().st_size / 1e6
        
        return {
            'csv_size_mb': round(csv_size, 2),
            'parquet_size_mb': round(parquet_size, 2),
            'compression_ratio': round(csv_size / parquet_size, 1),
            'rows': len(df),
            'columns': len(df.columns),
        }
    
    def read_parquet(self, path, columns=None, filters=None):
        '''Read Parquet with column pruning and filtering'''
        table = pq.read_table(path, columns=columns, filters=filters)
        return table.to_pandas()
    
    def inspect_metadata(self, path):
        '''Inspect Parquet file metadata'''
        pf = pq.ParquetFile(path)
        metadata = pf.metadata
        schema = pf.schema_arrow
        
        return {
            'num_rows': metadata.num_rows,
            'num_columns': metadata.num_columns,
            'num_row_groups': metadata.num_row_groups,
            'format_version': metadata.format_version,
            'created_by': metadata.created_by,
            'serialized_size': metadata.serialized_size,
            'columns': [
                {
                    'name': schema.field(i).name,
                    'type': str(schema.field(i).type),
                    'nullable': schema.field(i).nullable,
                }
                for i in range(len(schema))
            ],
        }
    
    def partition_write(self, df, path, partition_cols):
        '''Write partitioned Parquet dataset'''
        table = pa.Table.from_pandas(df)
        pq.write_to_dataset(
            table,
            root_path=path,
            partition_cols=partition_cols,
        )
        return {'path': path, 'partitions': partition_cols}
    
    def benchmark_read(self, path, n_iterations=5):
        '''Benchmark Parquet read performance'''
        import time
        
        times = []
        for _ in range(n_iterations):
            start = time.time()
            df = pd.read_parquet(path)
            elapsed = time.time() - start
            times.append(elapsed)
        
        return {
            'avg_time_ms': round(sum(times) / len(times) * 1000, 1),
            'min_time_ms': round(min(times) * 1000, 1),
            'rows': len(df),
            'columns': len(df.columns),
        }

# mgr = ParquetManager()
# result = mgr.csv_to_parquet("data.csv")
# metadata = mgr.inspect_metadata("data.parquet")
"""

    def show_code(self):
        print("=== Parquet Operations ===")
        print(self.CODE[:600])

ops = ParquetOperations()
ops.show_code()

Career Development Path

# career.py — IT career development with Parquet skills
import json

class CareerDevelopment:
    ROLES = {
        "data_engineer": {
            "name": "Data Engineer",
            "salary_range": "40,000-150,000 บาท/เดือน",
            "parquet_skills": [
                "Parquet file optimization (row group size, compression)",
                "Partitioning strategies (date, region, category)",
                "Schema evolution management",
                "Data pipeline: CSV/JSON → Parquet → Data Warehouse",
            ],
            "tools": "Spark, Airflow, dbt, Delta Lake, Iceberg",
        },
        "data_analyst": {
            "name": "Data Analyst",
            "salary_range": "25,000-80,000 บาท/เดือน",
            "parquet_skills": [
                "Read Parquet with Pandas/DuckDB",
                "Column pruning for fast queries",
                "BI tool integration (Metabase, Superset)",
            ],
            "tools": "Pandas, DuckDB, SQL, Tableau, Power BI",
        },
        "ml_engineer": {
            "name": "ML Engineer",
            "salary_range": "50,000-180,000 บาท/เดือน",
            "parquet_skills": [
                "Feature store with Parquet (Feast, Tecton)",
                "Training data management",
                "Dataset versioning (DVC, LakeFS)",
            ],
            "tools": "PyArrow, Spark ML, MLflow, Kubeflow",
        },
        "platform_engineer": {
            "name": "Data Platform Engineer",
            "salary_range": "60,000-200,000 บาท/เดือน",
            "parquet_skills": [
                "Data lakehouse architecture (Delta Lake, Iceberg, Hudi)",
                "Query engine optimization (Spark, Presto, Trino)",
                "Storage optimization (compaction, Z-ordering)",
            ],
            "tools": "Spark, Trino, Iceberg, Delta Lake, Kubernetes",
        },
    }

    LEARNING_PATH = {
        "beginner": {
            "level": "Beginner (0-6 เดือน)",
            "skills": ["Python + Pandas basics", "CSV vs Parquet", "Read/Write Parquet", "SQL basics"],
        },
        "intermediate": {
            "level": "Intermediate (6-18 เดือน)",
            "skills": ["Spark + PySpark", "Partitioning strategies", "Schema evolution", "Data pipeline (Airflow)"],
        },
        "advanced": {
            "level": "Advanced (18+ เดือน)",
            "skills": ["Delta Lake/Iceberg", "Query optimization", "Data lakehouse architecture", "Performance tuning"],
        },
    }

    def show_roles(self):
        print("=== Career Roles ===\n")
        for key, role in self.ROLES.items():
            print(f"[{role['name']}] ({role['salary_range']})")
            print(f"  Tools: {role['tools']}")
            print(f"  Parquet skills:")
            for skill in role['parquet_skills'][:2]:
                print(f"    • {skill}")
            print()

    def show_learning(self):
        print("=== Learning Path ===")
        for key, level in self.LEARNING_PATH.items():
            print(f"\n[{level['level']}]")
            for skill in level['skills']:
                print(f"  • {skill}")

career = CareerDevelopment()
career.show_roles()
career.show_learning()

Advanced Parquet Techniques

# advanced.py — Advanced Parquet techniques
import json

class AdvancedParquet:
    OPTIMIZATION = {
        "row_group_size": {
            "name": "Row Group Size",
            "description": "กำหนดขนาด row group — ส่งผลต่อ read performance",
            "recommendation": "128MB - 1GB per row group (default: 128MB ใน Spark)",
            "tradeoff": "ใหญ่ = compression ดีกว่า, เล็ก = predicate pushdown ดีกว่า",
        },
        "compression": {
            "name": "Compression Codec",
            "options": {
                "snappy": "เร็ว, compression ratio ปานกลาง — default ที่ดี",
                "zstd": "compression ดีกว่า snappy, เร็วพอ — แนะนำสำหรับ cold data",
                "gzip": "compression ดีที่สุด แต่ช้า — สำหรับ archive",
                "lz4": "เร็วที่สุด, compression น้อย — สำหรับ hot data",
            },
        },
        "partitioning": {
            "name": "Partitioning Strategy",
            "description": "แบ่งข้อมูลเป็น directories ตาม column values",
            "example": "data/year=2024/month=01/part-00000.parquet",
            "best_practices": [
                "Partition by date (year/month/day) — common สำหรับ time-series",
                "ไม่เกิน 3-4 levels — มาก partition = small files problem",
                "Cardinality ไม่สูงเกินไป — country (ดี) vs user_id (ไม่ดี)",
            ],
        },
    }

    TABLE_FORMATS = {
        "delta_lake": {
            "name": "Delta Lake",
            "description": "ACID transactions บน Parquet — Databricks ecosystem",
            "features": "Time travel, schema enforcement, MERGE, compaction",
        },
        "apache_iceberg": {
            "name": "Apache Iceberg",
            "description": "Open table format — vendor neutral, Netflix origin",
            "features": "Hidden partitioning, time travel, schema evolution",
        },
        "apache_hudi": {
            "name": "Apache Hudi",
            "description": "Incremental processing — Uber origin",
            "features": "Upserts, incremental queries, compaction",
        },
    }

    def show_optimization(self):
        print("=== Optimization Techniques ===\n")
        for key, opt in self.OPTIMIZATION.items():
            print(f"[{opt['name']}]")
            print(f"  {opt['description']}" if 'description' in opt else "")
            if 'recommendation' in opt:
                print(f"  Recommended: {opt['recommendation']}")
            print()

    def show_table_formats(self):
        print("=== Modern Table Formats (built on Parquet) ===")
        for key, fmt in self.TABLE_FORMATS.items():
            print(f"\n[{fmt['name']}]")
            print(f"  {fmt['description']}")
            print(f"  Features: {fmt['features']}")

adv = AdvancedParquet()
adv.show_optimization()
adv.show_table_formats()

Interview Questions

# interview.py — Parquet interview questions
import json

class ParquetInterview:
    QUESTIONS = {
        "q1": {
            "q": "Parquet กับ CSV ต่างกันอย่างไร? เมื่อไหร่ควรใช้อะไร?",
            "a": "Parquet: columnar, compressed, schema, fast analytics. CSV: text, human readable, simple. ใช้ Parquet: analytics, data warehouse, ML. ใช้ CSV: data exchange, small datasets, human editing.",
        },
        "q2": {
            "q": "Columnar storage ดีกว่า row-based อย่างไร สำหรับ analytical queries?",
            "a": "Analytical queries มักอ่านไม่กี่ columns จาก rows เยอะ. Columnar อ่านเฉพาะ columns ที่ต้องการ (column pruning). Compression ดีกว่า (same data type per column). Predicate pushdown กรองระดับ storage.",
        },
        "q3": {
            "q": "Row group ใน Parquet คืออะไร? ขนาดที่เหมาะสมเท่าไหร่?",
            "a": "Row group = logical horizontal partition ของ data. แต่ละ row group มี column chunks. ขนาดแนะนำ: 128MB-1GB. ใหญ่ = compression ดี แต่ memory สูง. เล็ก = predicate pushdown ดีแต่ overhead มาก.",
        },
        "q4": {
            "q": "Schema evolution ใน Parquet ทำอย่างไร?",
            "a": "เพิ่ม column: เขียน file ใหม่กับ column ใหม่ — files เก่าอ่านได้ (null สำหรับ column ใหม่). ลบ column: ไม่ต้องแก้ file — อ่านเฉพาะ columns ที่ต้องการ. เปลี่ยน type: ต้อง compatible (int32 → int64 ได้).",
        },
        "q5": {
            "q": "Delta Lake/Iceberg เพิ่มอะไรให้ Parquet?",
            "a": "ACID transactions: atomic writes, consistent reads. Time travel: query historical versions. Schema enforcement/evolution. MERGE/UPDATE/DELETE operations. Compaction: รวม small files. Metadata management: ไม่ต้อง list files ใน directory.",
        },
    }

    def show_questions(self):
        print("=== Interview Questions ===\n")
        for key, qa in self.QUESTIONS.items():
            print(f"Q: {qa['q']}")
            print(f"A: {qa['a'][:120]}...")
            print()

interview = ParquetInterview()
interview.show_questions()

FAQ - คำถามที่พบบ่อย

Q: Parquet เหมาะกับงานอะไร?

A: เหมาะมาก: Data analytics, Data warehouse, ML feature stores, Log storage ใช้ได้: ETL pipelines, Data lakehouse, BI dashboards ไม่เหมาะ: Real-time streaming (ใช้ Avro), small datasets (< 10MB ใช้ CSV ง่ายกว่า), OLTP (ใช้ database)

Q: ต้องรู้ Parquet ถึงจะได้งาน Data Engineer ไหม?

A: ไม่จำเป็นต้อง "เชี่ยวชาญ" แต่ต้อง "รู้จัก" — Parquet เป็นพื้นฐานของ data engineering สิ่งที่ต้องรู้: อ่าน/เขียน Parquet ด้วย Pandas/Spark, ข้อดีเทียบ CSV, partitioning basics เรียนเพิ่ม: Delta Lake/Iceberg, optimization, schema evolution — เพิ่มคะแนนสัมภาษณ์มาก

Q: DuckDB กับ Pandas อันไหนดีกว่าสำหรับ Parquet?

A: DuckDB: เร็วกว่ามากสำหรับ large files (> 1GB), ใช้ SQL ได้, memory efficient Pandas: ง่ายกว่า, ecosystem ใหญ่กว่า, ML integration ดีกว่า ใช้ DuckDB: analytical queries บน large Parquet files ใช้ Pandas: data manipulation, ML preprocessing, small-medium files

Q: Compression อันไหนดีที่สุด?

A: Snappy: default ที่ดี — balance ระหว่าง speed และ size (แนะนำสำหรับ Spark) Zstd: compression ดีกว่า Snappy 20-30%, เร็วพอ — แนะนำสำหรับ long-term storage Gzip: compression ดีที่สุด แต่ช้า — สำหรับ archive เท่านั้น ไม่ compress: ถ้าต้องการ read speed สูงสุดและ storage ไม่จำกัด

📖 บทความที่เกี่ยวข้อง

Parquet Format Automation Scriptอ่านบทความ → Parquet Format Micro-segmentationอ่านบทความ → Parquet Format Internal Developer Platformอ่านบทความ → Parquet Format Microservices Architectureอ่านบทความ → Parquet Format Log Management ELKอ่านบทความ →

📚 ดูบทความทั้งหมด →