Object Mapping Trực Quan và Fluent Queries cho Redis và Python
Tôi hào hứng giới thiệu Redis OM cho Python, một thư viện mới mạnh mẽ tập trung vào nhà phát triển cho Redis mang lại các tính năng như object mapping, validation dữ liệu, và nhiều hơn nữa.
Bản phát hành preview này của Redis OM cho Python cho phép bạn mô hình hóa dữ liệu với declarative models (mô hình khai báo) sẽ cảm thấy như ở nhà đối với người dùng của object-relational mappers (ORMs) như SQLAlchemy, Peewee, và Django ORM.
Nhưng còn nhiều hơn nữa! Mọi Redis OM model cũng là một Pydantic model, vì vậy bạn có thể dùng các tính năng validation dữ liệu mạnh mẽ và mở rộng của Pydantic. Hơn nữa, Redis OM model sẽ hoạt động ở bất cứ đâu mà một thư viện Python mong đợi Pydantic model. Vì vậy, bạn có thể dùng một Redis OM model với FastAPI để tự động validate và tạo tài liệu API cho các endpoint API.
Một tính năng khác thân thiết với trái tim tôi là Redis OM hỗ trợ fluent query expressions (biểu thức truy vấn fluent) và secondary indexes (chỉ mục thứ cấp). Redis OM cho Python cũng hỗ trợ cả lập trình asynchronous (asyncio) và synchronous trong cùng một thư viện. Và danh sách các tính năng tuyệt vời còn tiếp tục!
Tiếp tục đọc để tìm hiểu về cách tôi xây dựng thư viện này và một số chi tiết hậu trường về một vài tính năng chính. Hoặc, nếu bạn sẵn sàng chơi với code, hãy xem hướng dẫn getting started.
Declarative models cho Redis
Các nhà phát triển thường truy cập Redis thông qua một thư viện client để tạo Redis data structures (ví dụ: Hashes) và sau đó commands đối với chúng.
Nhiều người thích giao diện dựa trên lệnh này vì nó đơn giản hơn viết truy vấn SQL với cơ sở dữ liệu quan hệ. Nhưng khi nào bạn viết SQL lần cuối? Các nhà phát triển dùng framework web hiện đại xu hướng dùng ORMs thay vào đó, đặc biệt với declarative models.
Điều tôi yêu thích về ORMs là chúng loại bỏ rất nhiều phức tạp không liên quan đến vấn đề bạn đang cố gắng giải quyết. Chúng tôi tạo Redis OM để bạn cuối cùng có thể có cùng trải nghiệm với Redis.
Hashes hoặc JSON, lựa chọn của bạn
Redis OM cho Python bao gồm hai lớp cơ sở model bạn có thể dùng để xây dựng model của mình: HashModel và JsonModel.
Người dùng Redis open-source có thể dùng HashModel để lưu dữ liệu trong Redis như Hashes, trong khi người dùng có cài đặt module RedisJSON Redis hoặc đang dùng Redis Enterprise Cloud hoặc Software có thể dùng JsonModel để lưu dữ liệu bản địa như đối tượng JSON. Sẽ nói thêm về sự khác biệt giữa các lớp này sau, nhưng bây giờ, chúng ta sẽ dùng HashModel.
Định nghĩa model ngắn gọn
Nhìn vào ví dụ code Redis OM này định nghĩa một model Customer và dùng nó để lưu dữ liệu vào Redis:
Định nghĩa model ngắn gọn này ngay lập tức cho bạn các phương thức như `get()` và `save()`. Phía sau, các phương thức này quản lý dữ liệu trong Redis Hashes.
Redis OM làm nhiều hơn thế. Nó cũng tạo ra primary key toàn cầu duy nhất và có thể sắp xếp. Phần này siêu hữu ích, để tôi giải thích cách nó hoạt động.
Primary key toàn cầu duy nhất
Redis OM tự động tạo một primary key toàn cầu duy nhất cho mọi instance model. Bạn có thể dùng primary key này để lưu và truy xuất dữ liệu model trong Redis.
Các primary key này được đảm bảo toàn cầu duy nhất, nhưng chúng cũng được tạo hoàn toàn ở client mà không cần request nào đến Redis. Chúng cũng có thể sắp xếp (sortable) và compact. Tất cả điều này là nhờ spec Universally Unique Lexicographically Sortable Identifiers (ULID).
Redis OM primary keys là ULIDs, nhờ python-ulid. Bạn có thể đọc thêm về spec ULID ở đây. Rất cool!
Ngoài các tính năng persistence này, bạn còn có data validation với Pydantic. Hãy đào sâu vào cách validation hoạt động.
Data validation với Pydantic
Một sự khác biệt giữa Redis và cơ sở dữ liệu quan hệ là Redis không enforce (buộc tuân theo) schema, vì vậy bạn có thể viết một chuỗi trong Redis rồi ghi đè nó bằng một số sau. Điều này linh hoạt hơn cơ sở dữ liệu quan hệ, nhưng cũng có nghĩa là ứng dụng chịu trách nhiệm về data validation.
Chúng tôi nghĩ bạn không nên phải tự tìm ra cách tốt nhất để xử lý validation trong ứng dụng của mình, vì vậy mọi Redis OM model cũng là một Pydantic model. Điều này có nghĩa là bạn có validation của Pydantic dựa trên type hints trong model của bạn, và bạn có thể kiểm soát validation qua các hook Pydantic tiêu chuẩn, bao gồm custom validators.
Đây là một số code ví dụ cho thấy validation hoạt động như thế nào:
Nếu Redis OM cho Python chỉ cho bạn persistence methods và data validation, tôi đã nghĩ nó khá cool. Nhưng chúng tôi muốn xử lý thêm phức tạp cho bạn, và để làm điều đó chúng tôi cần giúp bạn viết expressive queries (truy vấn biểu đạt) giống như bạn dùng với ORM. Tiếp theo, tôi sẽ nói về cách các truy vấn này hoạt động.
Fluent query expressions
ORMs không chỉ cho bạn declarative models. Chúng cũng cung cấp một API cho phép bạn truy vấn dữ liệu dựa trên thuộc tính khác primary key. Tưởng tượng tìm tất cả customer trên một tuổi nhất định, customer đăng ký trước một ngày nhất định, v.v.
Out of the box (mặc định), Redis tuyệt vời ở việc lookup dữ liệu với primary key. Nó dù sao cũng là một key-value store có value là data structure. Nhưng Redis không bao gồm hệ thống truy vấn và secondary indexing, vì vậy nếu bạn muốn index và query dữ liệu, bạn phải tự quản lý index theo cách phức tạp.
Ở đây lại, chúng tôi muốn xử lý phức tạp này cho bạn, vì vậy chúng tôi xây dựng fluent query expressions trên đỉnh một module Redis thiết yếu: RediSearch. RediSearch là một module source-available cho bạn khả năng truy vấn và indexing bị thiếu ở Redis.
Hãy xem điều gì xảy ra nếu chúng ta đánh dấu một vài trường trên model Customer là `index=True`. Bây giờ, chúng ta có thể dùng model để truy vấn:
Cú pháp biểu thức này có thể trông quen thuộc – nó là sự kết hợp của mọi thứ tôi thích về Peewee, SQLAlchemy, và Django ORM.
Embedded models (Model nhúng)
Khi bạn mô hình hóa dữ liệu phức tạp với Redis, bạn chắc chắn muốn lưu dữ liệu nhúng (embedded data). Nếu bạn đang mô hình hóa dữ liệu khách hàng dùng Redis Hashes, bạn có thể muốn lưu dữ liệu như địa chỉ giao hàng của khách hàng trong Hash của một khách hàng riêng lẻ. Đáng tiếc, Redis Hashes không thể lưu nested containers (container lồng nhau) như Lists, Sets, hoặc Hashes khác, nên điều này không hoạt động.
Đây là nơi lưu dữ liệu như một đối tượng JSON bản địa (native JSON object) có nhiều ý nghĩa. Nếu bạn mô hình hóa dữ liệu khách hàng như một tài liệu JSON, bạn có thể nhúng bất cứ thứ gì bạn muốn bên trong bản ghi cho một khách hàng đơn lẻ.
Tuy nhiên, Redis không hỗ trợ JSON bản địa. Đây chính xác là lý do chúng tôi tạo module RedisJSON source-available. RedisJSON làm cho việc dùng Redis như một document database trở nên khả thi, lưu trữ và truy vấn các đối tượng JSON phức tạp dễ dàng.
Với Redis OM cho Python, nếu instance Redis của bạn có cài RedisJSON, bạn có thể dùng lớp JsonModel. Lớp model này cho phép bạn nhúng JsonModels bên trong JsonModels khác. Tưởng tượng customer có một mảng orders, mỗi order có một mảng items, và cứ thế.
Đây là embedded JSON models trông như thế nào với Redis OM cho Python:
Không chỉ bạn có sự linh hoạt để lưu trữ các đối tượng JSON phức tạp, Redis OM cho Python còn nhận thức được các cấu trúc lồng nhau đó và cho phép bạn viết biểu thức truy vấn đối với chúng. Awesome!
Thử Redis OM cho Python
Tôi hy vọng bạn có thể thấy tôi hào hứng đến mức nào về Redis OM cho Python. Tôi đã làm việc để mang một số thứ tốt nhất của hệ sinh thái Python hiện tại lại với nhau để xử lý phức tạp cho các nhà phát triển Redis mà, theo ý kiến của tôi, không ai nên phải đối mặt.
Nếu tôi đã kích thích sự hứng thú của bạn, hãy xem hướng dẫn getting started. Redis OM cho Python đang ở một giai đoạn rất sớm, mà chúng tôi gọi là "Preview." Vì vậy có chỗ thô ráp, bạn sẽ gặp bug, và chúng tôi vẫn đang làm việc để giao tài liệu hoàn chỉnh. Nhưng tầm nhìn đã có, và tôi khuyến khích bạn xem nó.
Cuối cùng, tôi sẽ nói rằng chúng tôi bắt đầu với declarative data models, nhưng chúng tôi còn nhiều hơn nữa muốn xây dựng – cả cho data modeling và hơn thế. Hãy theo dõi cho thêm tính năng Redis OM thú vị!