Thực thể Group Engagement

Một phần của tài liệu Xây dựng hệ quản trị đào tạo tích hợp mạng xã hội (Trang 113)

Thuộc tính Kiểu dữ liệu Mơ tả

groupId integer Định danh của Nhóm (khóa chính - khóa ngoại).

createdDate date Ngày cập nhật thơng tin (khóa chính).

totalMember integer Số lượng thành viên tính đến thời điểm cập nhật.

activeMember integer Số lượng thành viên có ít nhất một bài viết, bình

luận hoặc vote trong ngày. Bảng 97: Thực thể Group Growth.

Thuộc tính Kiểu dữ liệu Mơ tả

groupId integer Định danh của Nhóm (khóa chính - khóa ngoại).

userId integer Định danh của Người dùng (khóa chính - khóa

ngoại).

createdDate date Ngày cập nhật thơng tin (khóa chính).

totalPost integer Số lượng bài viết trong ngày của người dùng.

totalComment integer Số lượng bình luận trong ngày của người dùng.

totalVote integer Số lượng vote trong ngày của người dùng.

Bảng 98: Thực thể Group Contributor.Chú thích Enum: Chú thích Enum:

user_role  user

 admin

 Người dùng thông thường  Quản trị viên

notification_

type  - Hệ thống sẽ có phong phú các loại notification

tùy theo nghiệp vụ.

course_unit_ type  video  quiz  reference  assignment  Bài học video  Câu hỏi quiz

 Bài học dạng tài liệu tham khảo  Bài assignment evaluation_ status  None  Partial  Full

 Assignment chưa được đánh giá  Assignment được đánh giá một phần  Assignment được đánh giá tồn phần.

event_type  deadline

 startUnit

 Deadline đơn vị khóa học.  Đơn vị khóa học bắt đầu. group_member

_role

 normal  moderator

 Người dùng thơng thường.  Quản trị nhóm.

comment_type

 comment

 reply  answer

 Bình luận vào bài viết  Bình luận vào bình luận  Bình luận vào Q&A

vote_type

 post

 comment

 qa

 Vote vào bài viết  Vote vào bình luận  Vote vào Q&A Bảng 99: Các kiểu enum dùng trong hệ thống.

Hình 27: Kiến trúc hệ thống

Hệ thống mà đề tài luận văn xây dựng dựa trên kiến trúc monolith, trong đó trung tâm chính của kiến trúc là Application Server chứa các thành phần hiện thực logic chính của hệ thống. Ngồi ra, hệ thống cịn có các thành phần ngoại vi (external components) hỗ trợ cho application server và giao tiếp với application server thơng qua một hình thức giao tiếp nào đó (so với internal components giao tiếp với nhau thông qua lời gọi hàm). Chúng bao gồm:

 Socket.IO: giải pháp Websocket cho NodeJS. Socket.IO giúp đơn giản hóa việc hiện thực Websocket ở NodeJS. NestJS Framework còn cung cấp thêm một lớp adapter bao quanh Socket.IO giúp việc tích hợp với kiến trúc modular của NestJS thêm phần dễ dàng.

 ActionML: Giải pháp hiện thực Hệ thống gợi ý. Điểm mạnh của việc sử dụng ActionML đó chính là khả năng tùy chỉnh cao, như thay đổi thời gian tồn tại của dữ liệu (time-to-live), các sự kiện có tính chỉ thị (indicators) phong phú, định nghĩa các

luật lệ cho phù hợp với business hệ thống, cơ chế giới thiệu sản phẩm nếu dữ liệu thiếu thốn (popular, trending, hot), v.v.. Việc giao tiếp với ActionML Server (cịn gọi là Harness) thơng qua API cung cấp bởi ActionML.

 ElasticSearch: Giải pháp tìm kiếm cho phép chúng ta tìm kiếm dựa trên nhiều use-case khác nhau. ElasticSearch được giao tiếp chủ yếu thông qua API, được hỗ trợ giao diện bởi một thư viện trong hệ sinh thái NestJS.

 PostgreSQL: Cơ sở dữ liệu chính của hệ thống. Hệ thống sử dụng TypeORM để giúp hiện thực các câu query và transaction đơn giản và dễ dàng hơn.

 Duplicate Search Server: Server ngoại vi sử dụng FastAPI, một framework backend của Python, để hiện thực tính năng tìm kiếm các câu hỏi trùng nhau. Sở dĩ nhóm làm đề tài chọn framework này là vì bởi nhóm cần một wrapper server bao quanh các mơ hình Deep Learning có thể được set-up một cách nhanh chóng.

Application Server được xây dựng theo hướng module hóa nhất có thể. Kiến trúc được

chia thành các module dựa trên các tính năng chính. Có thể kể đến:

 Course Management Module: Hiện thực các tính năng của khóa học và quản lý các hoạt động liên quan đến khóa học.

 Group Management Module: Hiện thực các tính năng của nhóm và các hoạt động liên quan đến nhóm.

 User Management Module: Hiện thực tính năng quản lý người dùng và các hoạt động giữa người dùng với nhau.

 Authentication Module: Hiện thực tính năng xác thực và ủy quyền.

 Gamification Module: Hiện thực các tính năng gamification của khóa học, bao gồm tính năng Thành tựu (achievement) và bảng xếp hạng (leaderboard).

 Messaging Module: Hiện thực tính năng nhắn tin.

 Search Module: Hiện thực các tính năng tìm kiếm có trong hệ thống.  Notification Module: Hiện thực tính năng thơng báo đến người dùng.

Từng module đó lại được tiếp tục chia nhỏ thành các module con dựa trên thực thể chính liên quan. Lấy ví dụ, trong module quản lý khóa học: có thể được chia nhỏ thành module Khóa học, module Giáo viên, module Học sinh dựa trên thực thể chính của từng module đó.

6 Hiện thực

Trong chương này, nhóm làm đề tài sẽ trình bày chi tiết về các mẫu hiện thực được nhóm tìm hiểu và sử dụng để hiện thực các tính năng trong hệ thống.

Định nghĩa Endpoint để giao tiếp giữa phần back-end và phần front-end là một vấn đề khá quan trọng để đảm bảo q trình hiện thực được sn sẻ và độc lập giữa chúng. Trong quá trình định nghĩa và hiện thực các endpoint trong hệ thống, nhóm làm đề tài đi đến những quyết định sau:

 Tài nguyên REST sẽ ln được định nghĩa dưới hình thức số nhiều (ví dụ như courses, users) và có sử dụng tham số đường dẫn (path parameter, ví dụ courses/:courseId) để hiện thực việc lấy thơng tin ở một tài ngun có định danh xác định.

 Đối với các tài nguyên có quan hệ cha/con (một khóa học có nhiều đơn vị khóa học) thì API cho phép định nghĩa nested uri.

 Các method được cung cấp trong API bao gồm GET, POST, PUT và DELETE (Không hỗ trợ PUT) với ngữ nghĩa tương tự như đã được định nghĩa ở chuẩn RESTFul. Có một số trường hợp ngoại lệ đối với quy luật này, ví dụ đối với API search thì nhóm làm đề tài sử dụng POST thay vì GET bởi search query thường có nhiều tham số và các tham số này có thể nested (ví dụ như đối tượng lọc filter có thể chứa tham số con như tên trường được lọc, toán tử so sánh - bằng eq, lớn hơn ge, nhỏ hơn le). Rất khó để có thể định nghĩa một mơ hình tham số Query cho GET Request thỏa mãn mục đích trên. Request Body là một sự lựa chọn phù hợp hơn để chứa thơng tin nested như vậy và do đó nhóm làm đề tài sử dụng POST Request.

 Đối với GET, tham số truyền vào có thể là tham số Đường dẫn (Path) đối với trường hợp lấy thơng tin ở một tài ngun đã có định danh hoặc Truy vấn (Query) để lấy tồn bộ thơng tin các tài ngun, được lọc ra bởi các tham số định nghĩa trong Truy vấn. Từ nhận xét trên, ta có thể chia GET Request thành hai loại mà ta tạm gọi là GET API (lấy thông tin một tài nguyên cụ thể) và LISTING API (lấy danh sách các entity trong tài nguyên nhất định).

 Đối với POST, tham số truyền vào chính là tham số ở phần Thân (body) của Request. POST Request được sử dụng xuyên suốt trong hệ thống để hiện thực quá trình thêm dữ liệu. Ngoài ra POST cũng được sử dụng để thay thế GET Request trong trường hợp tham số Truy vấn không đủ khả năng biểu diễn nghiệp vụ, hoặc các nghiệp vụ đặc biệt khơng thể diễn tả bằng các method sẵn có (ví dụ như trường hợp người dùng sắp xếp các đơn vị khóa học trong khóa học).

 Đối với method PATCH, nhóm làm đề tài tuân thủ quy luật thiết kế đó là có tham số Đường dẫn đến định danh của tài nguyên cũng như là phần Thân chứa một phần hoặc tồn bộ dữ liệu có thể cập nhật – hay còn gọi là partial update.

 Đối với method DELETE, nhóm làm đề tài cũng tuân theo quy chuẩn thiết kế đó là chỉ hỗ trợ xóa cho từng tài nguyên có định danh bằng tham số Đường dẫn (khơng cho xóa nhiều tài nguyên cùng lúc).

 REST là một chuẩn định nghĩa API với bản chất là các tài nguyên phải stateless, tức là khơng giữ trạng thái của client ở server. Hay nói cách khác, các request phải chứa đầy đủ thơng tin của tài nguyên, bao gồm cả thông tin người dùng. Tuy nhiên, đây cũng là một hạn chế bởi vì đơi khi nghiệp vụ bắt buộc chúng ta phải trả về thông tin khác nhau

cho từng người dùng khác nhau (ví dụ như thơng tin Nhóm có được bookmark bởi người dùng hiện tại hay khơng). Nhóm làm đề tài quyết định thỏa hiệp ở chỗ sẽ vi phạm nguyên tắc này đối với những trường hợp cần phải có thơng tin người dùng đăng nhập, tuy nhiên sẽ thực hiện việc tách rời API để đảm bảo đa số các endpoint sẽ stateless nhất có thể.

6.2 Cơ sở dữ liệu

Q trình hiện thực sơ đồ luận lý ERD thành cơ sở dữ liệu vật lý đã tạo cơ hội cho nhóm làm đề tài áp dụng các mẫu và phương pháp hiện thực khác nhau đáp ứng được phong phú các use-case phát sinh trong hệ thống.

6.2.1 Sử dụng kiểu dữ liệu mở rộng

Các kiểu dữ liệu mở rộng của Postgres như enum, array và jsonb được nhóm làm đề tài sử dụng với tần suất cao khi hiện thực hệ thống. Mặc dù chúng không nằm trong chuẩn SQL và do đó sẽ gây cản trở trong việc chuyển đổi cơ sở dữ liệu nếu có nhu cầu sau này, các kiểu dữ liệu trên tỏ ra rất hữu dụng và giảm bớt thời gian phát triển của hệ thống.

Kiểu dữ liệu phân loại là một kiểu dữ liệu mà ở đó thuộc tính chỉ nằm trong một số các giá trị nhất định. Đây là kiểu dữ liệu khá phổ biến bởi vì trong thực tế, con người thường có xu hướng phân loại thực thể để dễ dàng lý luận về chúng. Việc mơ hình kiểu dữ liệu này thường được thực hiện bằng một trong hai cách truyền thống sau:

 Định nghĩa kiểu ở application logic (đa số các ngơn ngữ lập trình đều hỗ trợ kiểu dữ liệu này) và chuyển đổi chúng thành các giá trị dạng số hoặc chữ để lưu trữ ở cơ sở dữ liệu. Nhược điểm rõ ràng của cách làm này đó chính là các giá trị lưu trữ ở cơ sở dữ liệu sẽ trở nên tối nghĩa và chỉ có ý nghĩa khi được chuyển thành kiểu tương ứng ở application. Ngoài ra, về bản chất thì giá trị lưu trữ khơng hề bị ràng buộc, chúng ta hoàn toàn phụ thuộc vào tầng application xử lý việc này.

 Chuyển thành bảng riêng biệt có quan hệ 1..n với bảng ban đầu. Đây là cách làm chuẩn tắc được sử dụng nhiều trong công nghiệp. Tuy nhiên, cách làm này rõ ràng đánh đổi về mặt hiệu năng khi mà ta cần tốn một phép join thì mới có thể lấy được dữ liệu mong muốn.

Hình 28: Mơ hình kiểu enum dưới dạng bảng riêng biệt

Kiểu dữ liệu enum của Postgres giúp đáp ứng được yêu cầu ràng buộc về số lượng giá trị có thể nhận được mà vẫn đảm bảo về mặt hiệu năng khi đọc. Enum là một kiểu dữ liệu do người dùng tự định nghĩa và do đó nếu chúng ta có nhu cầu muốn thay đổi giá trị phân loại thường xun thì giải pháp này khơng q tốt. Vì về tính chất là một luận văn, phần mềm khơng có tính chất tiến hóa khơng ngừng như trong cơng nghiệp, giải pháp này tỏ ra khá tốt và hữu dụng.

Ngồi ra, Postgres cịn hỗ trợ hai kiểu dữ liệu mở rộng khác là array và jsonb. Array là

kiểu dữ liệu cho phép chúng ta lưu trữ một danh sách giá trị trong cùng một trường dữ liệu. Jsonb là kiểu dữ liệu cho phép ta lưu trữ dữ liệu dạng JSON ở trong trường dữ liệu tương tự như một cơ sở dữ liệu phi quan hệ. Có thể thấy chúng đã vi phạm phần nào nguyên tắc Normal Form khi cho phép một trường dữ liệu lưu trữ nhiều giá trị khác nhau. Tuy nhiên, chúng mang đến sự đơn giản khi hiện thực, đặc biệt là khi nhóm thực thể được rút gọn thành các kiểu dữ liệu này tương đối riêng biệt và độc lập.

Lấy ví dụ với một nhóm thực thể mơ tả ở ERD liên quan đến bài quiz như sau:

Hình 29: Các thực thể liên quan đến Quiz

Mơ hình cấu trúc này thành các bảng độc lập là khơng q khó tuy nhiên sẽ mang đến sự phức tạp khi sử dụng chúng để hiện thực các tính năng liên quan. Nhóm làm đề tài nhận thấy cấu trúc này tương đối riêng biệt (ngoại trừ Quiz Attempt có quan hệ với User). Việc chuyển đổi thành kiểu JSON có thể được hiện thực như sau:

Hình 30: Cấu trúc JSON lưu trữ ở trường dữliệu properties của thực thể quiz. liệu properties của thực thể quiz.

Vì hệ thống hiện thực bằng ngơn ngữ Typescript nên việc làm việc với các cấu trúc JSON như trên khá đơn giản và dễ dàng. Ngồi ra, một ích lợi nữa của việc lưu trữ như trên là hiệu năng đọc sẽ được cải thiện khá nhiều.

Ngoài ra, jsonb cịn rất hữu ích trong trường hợp việc mơ hình thực thể gần như là bất khả thi. Lấy ví dụ thực thể Notification là thông báo được gửi đi đến người dùng khi có một event nhất định nào đó xảy ra trong hệ thống. Ta nhận thấy là có hằng hà sa số các event kiểu như vậy, mỗi loại lại cần phải lưu trữ các trường dữ liệu khác nhau, phục vụ mục đích hiển thị cũng như chuyển trang khi người dùng bấm vào. Giải pháp đó chính là ta định nghĩa một trường dữ liệu properties kiểu jsonb lưu trữ được hết toàn bộ trường hợp và dựa vào một trường chỉ định (indicator field) để chỉ ra thực thể hiện tại thuộc loại nào mà xử lý cho phù hợp ở application logic. Vì tác vụ update vào các giá trị properties này là hầu như khơng bao giờ xảy ra, đây có thể xem là một ứng dụng phù hợp nhất cho kiểu dữ liệu jsonb. Kiểu dữ liệu này sẽ không phù hợp trong trường hợp dữ liệu có nhu cầu update một phần nhiều lần. Ở ví dụ bài quiz ở trên, vì nhóm làm đề tài hiện thực tác vụ update các câu hỏi của bài quiz bằng cách cho UI gửi lại tồn bộ thơng tin câu hỏi – đáp án dưới dạng JSON trả về server, hệ thống vẫn tránh được thao tác cập nhật một phần đối với kiểu dữ liệu này.

Hình 31: Lưu trữ thơng tin notification dưới dạng json

6.2.2 Phi chuẩn hóa dữ liệu

Chuẩn hóa dữ liệu là một kỹ thuật trong cơ sở dữ liệu nhằm loại bỏ dư thừa và loại bỏ các dị thường (anomaly) khi cập nhật và xóa dữ liệu. Vấn đề dư thừa khơng cịn là vấn đề quan trọng hiện nay khi mà bộ nhớ khơng cịn là một tài nguyên khan hiếm. Tuy nhiên, loại bỏ dị thường vẫn là một lợi ích quan trọng mà chuẩn hóa dữ liệu mang lại. Dị thường xảy ra khi dữ liệu được lặp lại ở nhiều chỗ khác nhau trong cơ sở dữ liệu. Khi đó, việc cập nhật nếu khơng cẩn thận chỉ cập nhật dữ liệu ở một nơi sẽ dẫn đến sự thiếu tính nhất quán trong hệ thống.

Một ví dụ thực tiễn cho việc này đã được nhóm làm đề tài rút ra được, đó chính là sự có mặt của các hệ cơ sở dữ liệu phụ như ElasticSearch (cơng cụ mà nhóm sử dụng để hiện thực chức năng tìm kiếm). Rõ ràng, chúng ta phải lưu trữ lại các thông tin của thực thể trong cơ sở dữ liệu chính vào cơ sở dữ liệu để phục vụ mục đích tìm kiếm. Việc cập nhật này có thể được thực hiện đồng bộ, bất đồng bộ, hoặc thông qua một tác vụ lặp đi lặp lại. Dù cho cơ chế có như thế nào, logic cập nhật dữ liệu từ chỗ đơn giản thông qua một tác vụ UPDATE SQL thông thường trở nên phức tạp hơn rất nhiều. Tồi tệ hơn, các hệ cơ sở dữ liệu NoSQL như ElasticSearch thường khơng có khái niệm quan hệ. Do đó để có thể biểu diễn được mối quan hệ 1..N hay M..N trong sơ đồ ERD, ta thường phải sử dụng cơ chế lưu trữ danh sách các đối tượng lồng nhau (nested objects). Giả sử ta có một thơng tin mapping của trường dữ liệu lưu trữ danh sách thành viên của index Nhóm (Group) như sau:

Một phần của tài liệu Xây dựng hệ quản trị đào tạo tích hợp mạng xã hội (Trang 113)

Tải bản đầy đủ (PDF)

(185 trang)