Tạo batch (data appender) trong EzyPlatform plugin
Back To Blogspersonal_post_word_counts đã tạo trước đó nhé.Mục tiêu
Của bài này là giúp các bạn:
- Tạo được lớp DataAppender để lưu số từ có trong bài viết vào bảng
personal_post_word_counts. - Tắt bật DataAppender.
Tạo lớp DataAppender
Đầu tiên chúng ta hãy tạo lớp AdminPersonalPostHistoryRepository với nội dung như sau:
package org.youngmonkeys.personal.admin.repo; import com.tvd12.ezydata.database.EzyDatabaseRepository; import com.tvd12.ezyfox.database.annotation.EzyQuery; import com.tvd12.ezyfox.database.annotation.EzyRepository; import com.tvd12.ezyfox.util.Next; import org.youngmonkeys.ezyarticle.sdk.entity.PostHistory; import java.util.List; @EzyRepository public interface AdminPersonalPostHistoryRepository extends EzyDatabaseRepository<Long, PostHistory> { @EzyQuery( "SELECT e FROM PostHistory e " + "WHERE e.id > ?0 " + "ORDER BY e.id ASC" ) List<PostHistory> findByIdGt(long idGt, Next next); }
Lớp này sẽ cung cấp hàm findByIdGt để lấy được danh sách các bài viết theo chiều id tăng dần đến id lớn nhất, việc này đảm bảo chúng ta sẽ duyệt qua được tất cả các lịch sử bài viết và không lặp lại.
Tiếp theo chúng ta hãy tạo lớp AdminPersonalPostWordCountDataAppender với nội dung như sau:
package org.youngmonkeys.personal.admin.appender; import com.fasterxml.jackson.databind.ObjectMapper; import com.tvd12.ezyfox.bean.annotation.EzySingleton; import com.tvd12.ezyfox.util.Next; import org.youngmonkeys.ezyarticle.sdk.entity.PostHistory; import org.youngmonkeys.ezyplatform.admin.appender.AdminDataAppender; import org.youngmonkeys.ezyplatform.admin.service.AdminSettingService; import org.youngmonkeys.ezyplatform.time.ClockProxy; import org.youngmonkeys.personal.admin.repo.AdminPersonalPostHistoryRepository; import org.youngmonkeys.personal.admin.repo.AdminPersonalPostWordCountRepository; import org.youngmonkeys.personal.entity.PersonalPostWordCount; import java.util.Arrays; import java.util.List; import static com.tvd12.ezyfox.io.EzyLists.last; import static org.youngmonkeys.ezyplatform.constant.CommonConstants.LIMIT_100_RECORDS; @EzySingleton public class AdminPersonalPostWordCountDataAppender extends AdminDataAppender<PostHistory, PersonalPostWordCount, Long> { private final ClockProxy clock; private final AdminPersonalPostHistoryRepository postHistoryRepository; private final AdminPersonalPostWordCountRepository postWordCountRepository; public AdminPersonalPostWordCountDataAppender( ClockProxy clock, ObjectMapper objectMapper, AdminSettingService settingService, AdminPersonalPostHistoryRepository postHistoryRepository, AdminPersonalPostWordCountRepository postWordCountRepository ) { super(objectMapper, settingService); this.clock = clock; this.postHistoryRepository = postHistoryRepository; this.postWordCountRepository = postWordCountRepository; } @Override protected boolean defaultStarted() { return true; } @Override protected void addDataRecord(PersonalPostWordCount dataRecord) { postWordCountRepository.save(dataRecord); } @Override protected PersonalPostWordCount toDataRecord( PostHistory value ) { long postId = value.getParentId(); String content = value.getContent(); long wordCount = Arrays .stream(content.trim().split("\s+")) .filter(s -> !s.isEmpty()) .count(); logger.info( "post history id: {}, post id: {}, word count: {}", value.getId(), postId, wordCount ); PersonalPostWordCount entity = new PersonalPostWordCount(); entity.setPostId(postId); entity.setWordCount(wordCount); entity.setUpdatedAt(clock.nowDateTime()); return entity; } @Override protected List<PostHistory> filterValueList( List<PostHistory> valueList ) { return valueList; } @Override protected List<PostHistory> getValueList(Long pageToken) { return postHistoryRepository.findByIdGt( pageToken, Next.limit(LIMIT_100_RECORDS) ); } @Override protected Long extractNewLastPageToken( List<PostHistory> valueList, Long currentLastPageToken ) { return valueList.isEmpty() ? currentLastPageToken : last(valueList).getId(); } @Override protected Long defaultPageToken() { return 0L; } @Override protected Class<Long> pageTokenType() { return Long.class; } @Override protected String getAppenderNamePrefix() { return "personal_post_word_count"; } }
Lớp này tương đối phức tạp, nó sẽ làm một số việc sau:
1. Thừa kế lớp AdminDataAppender cơ sở, trong lớp cơ sở này sẽ cài đặt sẵn các nghiệp vụ để lưu lại các id đã được duyệt qua mà EzyPlatform gọi nó là pageToken. Các tham số generics bao gồm
PostHistory: Là Entity nguồn, tức là chúng ta sẽ lấy dữ liệu từPostHistory.PersonalPostWordCount: Là Entity đích, tức là chúng ta sẽ chuyển đồi dữ liệu từPostHistorysangPersonalPostWordCountđể lưu vào cơ sở dữ liệu.Long: Là kiểu giá trị của pageToken, thực tế khi lưu xuống cơ sở dữ liệu (vào bảngezy_settings) page token sẽ được chuyển sang dạng text.
2. Cài đặt các hàm thao tác với page token:
extractNewLastPageToken: Để lấy ra page token từ danh sách dữ liệu đã được lấy ra, ở đây chúng ta lấy ra id của phần tử cuối cùng trong danh sách post history được lấy ra.defaultPageToken: Ở lần đầu tiên appender được chạy thì nó sẽ chưa có page token, ở đây chúng ta đặt bằng 0, nghĩa là appender sẽ lấy từ bản ghi đầu tiên của post history.pageTokenType: Trả về kiểu của page token, ở đây làLong.
3. Hàm getAppenderNamePrefix trả về tên của appender, lát nữa chúng ta sẽ thấy tác dụng của nó.
4. Hàm getValueList trả về danh sách các post history cần được duyệt. Lưu ý rằng tất cả các appender của EzyPlatform đều sử dụng chung 1 luồng duy nhất, vậy hãy lấy một lượng vừa phải số bản ghi cần xử lý để nhường tài nguyên cho các appender khác.
5. Hàm filterValueList dùng để lọc ra các post history thoả mãn điều kiện nào đó, ở đây chúng ta sẽ đếm từ của mọi bài viết.
- Hàm
toDataRecorddùng để chuyển đổi từPostHistorysangPersonalPostWordCount. Ở đây chúng ta chỉ đơn giản là đếm số lượng từ có trong nội dung của post history và tạo thành đối tượngPersonalPostWordCount. Lưu ý rằng nghiệp vụ đếm từ rất phức tạp tuỳ theo ngôn ngữ mà được coi thế nào là "một từ", ví dụ Việt Nam thì ngăn cách nhau bởi dấu phẩy, nhưng Trung Quốc có khi lại khác. - Hàm
addDataRecord: Dùng để lưuPersonalPostWordCountđược tạo ra vào cơ sở dữ liệu thông quapostWordCountRepository.
8. Hàm defaultStarted chỉ định rằng AdminPersonalPostWordCountDataAppender sẽ được chạy ngay khi EzyPlatform khởi động.
Bây giờ hãy chạy lại PersonalAdminPluginStartupTest và bạn sẽ thấy log hiện ra:
Và khi truy vấn cơ sở dữ liệu bạn sẽ nhận được kết quả:
Bật tắt DataAppender
EzyPlatform đã cung cấp sẵn tính năng này, bạn chỉ cần truy cập vào phần Cài đặt - Thông thường sau đó kéo xuống phần Các trình thêm dữ liệu và nhấn vào nút hiện, lú này bạn có thể thấy appender personal_post_word_count mà chúng ta đã đặt tên:
Bạn có thể nhấn vào:
Stop (Dừng): để dừng lại appender.Restart (Khởi động lại): Để khởi động lại appender, trên thực tế nó làm 2 thao tác là dừng vào chạy appender.Reload (Tải lại): Để chạy lại appender từ đầu, về bản chất nó cài lại page token về null và chúng ta sẽ chạy từ đầu, nó có thể gây trùng lặp dữ liệu khi chạy lại nên bạn hãy cân nhắc cần thận.