Cấu hình chiến lược ghi và thuộc tính khóa cho bảng Hudi
Trước khi tạo bảng, ta cần xác định chiến lược ghi (Write Strategy) phù hợp với use-case của hệ thống Lakehouse. Có hai lựa chọn chính: Copy On Write (COW) và Merge On Read (MOR).
Copy On Write (COW) đảm bảo tính nhất quán mạnh mẽ (strong consistency) và tối ưu cho các truy vấn đọc toàn bộ bảng (batch reads), nhưng tốc độ ghi và cập nhật (upsert) sẽ chậm hơn do phải ghi lại toàn bộ file data khi có thay đổi.
Merge On Read (MOR) tách biệt dữ liệu (data) và chỉ mục (index) ra hai file riêng biệt, cho phép ghi và cập nhật cực nhanh, nhưng đọc dữ liệu cần merge dữ liệu mới và cũ, phù hợp cho workload có tần suất cập nhật cao (near real-time).
Trong phần này, ta sẽ chọn chiến lược Merge On Read (MOR) để chuẩn bị cho các thao tác Upsert và Update ở Phần 4, đồng thời định nghĩa rõ ràng thuộc tính Khóa chính (Primary Key).
Tham số cấu hình bắt buộc cho bảng Hudi bao gồm: hoodie.table.type để xác định loại bảng, hoodie.datasource.write.precombine.field để xử lý trùng lặp khi ghi, và hoodie.datasource.write.recordkey.field để định danh duy nhất bản ghi.
Việc cấu hình đúng các tham số này ngay từ đầu sẽ giúp Spark Engine tự động quản lý metadata, versioning và compaction mà không cần can thiệp thủ công.
Tạo bảng Hudi đầu tiên bằng Spark SQL
Sử dụng Spark SQL là cách trực quan nhất để tạo bảng Hudi trong môi trường Lakehouse. Câu lệnh CREATE TABLE sẽ tự động kích hoạt engine Hudi nếu ta khai báo đúng STORED AS.
Chúng ta sẽ tạo một bảng mẫu tên là rides_hudi để lưu trữ dữ liệu đi xe, với cấu trúc gồm ID chuyến đi, thời gian, giá tiền và vị trí.
Cú pháp tạo bảng yêu cầu khai báo rõ ràng đường dẫn lưu trữ (Base Path) trên HDFS hoặc Local Filesystem, nơi các file .parquet và .hoodie sẽ được sinh ra.
Dưới đây là câu lệnh Spark SQL hoàn chỉnh để tạo bảng với chiến lược MOR, khóa chính là trip_id và trường ts dùng để precombine (giữ bản ghi mới nhất dựa trên thời gian).
spark.sql("CREATE TABLE rides_hudi (trip_id STRING, timestamp STRING, amount DOUBLE, source STRING, destination STRING) USING hudi OPTIONS (hoodie.table.type = 'MERGE_ON_READ', hoodie.datasource.write.recordkey.field = 'trip_id', hoodie.datasource.write.precombine.field = 'timestamp', hoodie.datasource.write.keygenerator.class = 'org.apache.hudi.keygen.SimpleKeyGenerator', hoodie.compaction.async.enabled = 'true', hoodie.compaction.inline.enabled = 'false') LOCATION '/home/ubuntu/hudi-data/rides'")
Kết quả mong đợi: Spark trả về thông báo "Table 'rides_hudi' created successfully" và trong thư mục /home/ubuntu/hudi-data/rides sẽ xuất hiện thư mục .hoodie chứa metadata của bảng, cùng với các file parquet trống.
Verify cấu trúc bảng và metadata
Sau khi tạo bảng, cần kiểm tra xem Spark đã nhận diện đúng định dạng Hudi và các thuộc tính metadata đã được ghi vào Hive Metastore chưa.
Thực hiện câu lệnh DESCRIBE FORMATTED để xem chi tiết thông tin bảng, bao gồm Storage Provider, Location, và các Key Generator đã cấu hình.
spark.sql("DESCRIBE FORMATTED rides_hudi").show(false)
Kết quả mong đợi: Một bảng hiển thị các dòng key và value. Dòng Provider phải hiển thị hudi, dòng Location khớp với đường dẫn đã định nghĩa, và dòng hoodie.table.type phải là MERGE_ON_READ.
Chuẩn bị dữ liệu mẫu và nhập liệu ban đầu
Để nhập dữ liệu vào bảng Hudi vừa tạo, ta cần một tập dữ liệu nguồn (Source Data) ở định dạng phổ biến như CSV. Hudi có khả năng đọc trực tiếp file CSV và chuyển đổi sang định dạng Parquet nội bộ.
Trước tiên, tạo file CSV mẫu chứa dữ liệu giao dịch ban đầu với cấu trúc trường khớp chính xác với schema của bảng rides_hudi.
Dữ liệu này sẽ bao gồm 5 bản ghi với các trip_id duy nhất để đảm bảo thao tác nhập liệu đầu tiên (Insert) diễn ra mượt mà mà không có xung đột khóa.
Thực hiện lệnh cat để tạo file CSV tại đường dẫn /home/ubuntu/data_source/rides_initial.csv.
cat > /home/ubuntu/data_source/rides_initial.csv
Kết quả mong đợi: File CSV được tạo thành công, có thể kiểm tra bằng lệnh cat /home/ubuntu/data_source/rides_initial.csv để xem nội dung.
Thực thi lệnh nhập dữ liệu (Insert) vào Hudi
Sử dụng lệnh INSERT INTO ... SELECT của Spark SQL để đọc dữ liệu từ file CSV và ghi vào bảng Hudi. Đây là thao tác Write đầu tiên của bảng.
Spark sẽ tự động chia nhỏ dữ liệu thành các partition file, tạo ra các commit đầu tiên (ví dụ: commit 1), và ghi metadata vào thư mục .hoodie.
Lưu ý: Khi nhập vào bảng Hudi, ta không cần khai báo lại OPTIONS vì chúng đã được định nghĩa lúc CREATE TABLE. Spark sẽ đọc cấu hình từ Hive Metastore.
spark.sql("INSERT INTO rides_hudi SELECT * FROM csv.`/home/ubuntu/data_source/rides_initial.csv`")
Kết quả mong đợi: Console hiển thị thông báo Executed Insert statement hoặc số lượng row đã ghi thành công. Không xuất hiện lỗi về schema mismatch hoặc primary key violation.
Verify dữ liệu đã nhập và cơ chế phân vùng
Kiểm tra số lượng bản ghi thực tế trong bảng để xác nhận thao tác insert đã hoàn tất.
spark.sql("SELECT COUNT(*) FROM rides_hudi").show()
Kết quả mong đợi: Trả về số 5, tương ứng với 5 dòng dữ liệu trong file CSV.
Kiểm tra cấu trúc vật lý trên disk để thấy các file data đã được tạo ra dưới dạng .parquet và các file metadata .hoodie (commit metadata).
find /home/ubuntu/hudi-data/rides -type f -name "*.parquet" | head -5
find /home/ubuntu/hudi-data/rides/.hoodie -type f | head -5
Kết quả mong đợi: Lệnh find trả về danh sách các file parquet chứa dữ liệu và các file xxx.commit trong thư mục .hoodie, chứng tỏ Hudi đã quản lý phiên bản dữ liệu.
Quét dữ liệu bằng SELECT * FROM để đảm bảo dữ liệu có thể đọc được ngay lập tức (Read consistency) mà không cần compaction thủ công.
spark.sql("SELECT * FROM rides_hudi ORDER BY trip_id").show(false)
Kết quả mong đợi: Hiển thị đầy đủ 5 dòng dữ liệu với các cột trip_id, timestamp, amount, source, destination chính xác như trong file CSV gốc.
Tích hợp và kiểm tra qua Hive Metastore
Hudi sử dụng Hive Metastore (HMS) hoặc Spark Catalog để quản lý metadata của bảng. Việc này cho phép các công cụ khác như Presto, Trino hoặc Hive CLI truy vấn dữ liệu Hudi mà không cần biết đến engine Spark.
Trong môi trường Ubuntu 24.04 với Spark standalone hoặc YARN, Hive Metastore thường chạy trên cổng 9083. Cần đảm bảo Spark được cấu hình để kết nối với Hive Metastore.
Kiểm tra xem bảng rides_hudi đã được ghi vào Hive Metastore chưa bằng cách sử dụng công cụ beeline hoặc truy vấn trực tiếp qua Spark SQL với namespace.
Sử dụng lệnh SHOW TABLES trong Spark SQL để liệt kê tất cả các bảng trong database hiện tại, xác nhận bảng mới xuất hiện.
spark.sql("SHOW TABLES").show()
Kết quả mong đợi: Danh sách bảng hiển thị rides_hudi cùng với database (thường là default).
Để kiểm tra chi tiết metadata được lưu trong Hive Metastore (bao gồm cả các tham số Hudi đặc thù), ta có thể truy vấn bảng hệ thống information_schema.tables` hoặc sử dụng DESCRIBE EXTENDED.
spark.sql("DESCRIBE EXTENDED rides_hudi").show(false)
Kết quả mong đợi: Một bảng dài liệt kê thông tin cơ bản và phần Table Properties chứa các key-value của Hudi như hoodie.table.type=MERGE_ON_READ, hoodie.datasource.write.recordkey.field=trip_id.
Đây là bước quan trọng để xác nhận rằng hệ thống Lakehouse đã sẵn sàng cho các thao tác phức tạp như Upsert, Update, và Delete trong các phần tiếp theo, vì metadata này là cơ sở để Hudi xác định vị trí dữ liệu cần sửa đổi.
Qua các bước trên, ta đã hoàn thành việc khởi tạo kho dữ liệu, thiết lập chiến lược ghi MOR, và nhập dữ liệu ban đầu thành công. Môi trường đã sẵn sàng cho việc thực thi các thao tác cập nhật dữ liệu.
Điều hướng series:
Mục lục: Series: Triển khai Database Lakehouse với Apache Hudi và Ubuntu 24.04
« Phần 2: Cài đặt và cấu hình Apache Hudi trên cụm Ubuntu
Phần 4: Thực thi các thao tác Upsert, Cập nhật và Xóa dữ liệu »