Elixir - Lưu trữ dữ liệu trên RAM với ETS
- May 12, 2018
ETS là gì?
Có lẽ các bạn đã nghe qua về redis hoặc memcache, hoặc là cả hai. Còn nếu bạn chưa nghe tới bao giờ thì đó là những cơ sở dữ liệu lưu trữ trên RAM với ưu điểm là tốc độ truy xuất cực kỳ nhanh. ETS - Erlang Term Service - cũng là một CSDL lưu trữ trên RAM (in-ram DB) nhưng khác ở chỗ là ETS có sẵn khi cài Elixir/Erlang và bạn chẳng phải mất công cài đặt, cấu hình như 2 anh trên kia, nhà trồng được việc gì phải ngại.
Đặc điểm của em nó là:
- Không cần cài đặt
- Dữ liệu lưu trữ trên RAM và mất đi khi process kết thúc
- Dữ liệu lưu trữ dạng
key-value valuecó thể làset,ordered_set,bag,duplicated_bag- Kiểu dữ liệu của
valuetrên cùng 1 bảng là giống nhau và đuợc khai báo khi tạo bảng.
Các thao tác trong ETS
1. Tạo bảng
iex> :ets.new(:cache, [:set, :protected, :named_table])
**Syntax: ** :ets.new(ten_bang, [type, access, name_table])
typelà kiểu dữ liệu củavaluelưu trong bảngsetlà kiểu dữ liệu, chú này chung thuỷ chỉ có 1 value cho 1 key và key là duy nhất, không bị trùng.ordered_setthằng em nghiêm túc củaset, khác thằng anh ở chỗ đuợc tự động order khi thêm data vào.bagkhác vớisetở chỗ chú này chơi harem, cho phép nhiều value cho cùng 1 key, tuy nhiên các value không đuợc trùng nhau.duplicated_bagthằng này ăn tạp giốngbagnhưng cho phép value trùng nhau
accessgiới hạn khả năng truy xuất dữ liệu từ bảng, cũng khá dễ nhớpublic: hàng công cộng, chú process nào thích nhìn (đọc), sờ (ghi) gì anh cho hếtprotected: các chú chỉ đuợc nhìn thôi, anh sở hữu thì anh đuợc sờprivate: anh giấu hết, chỉ có anh mới đuợc nhìn và sờ, các chú đi ra chỗ khác
named_tableCái này tuỳ chọn, bình thuờng thì sẽ trả về 1 id dùng để truy xuất vào table. Nếu thêm option này vào thì có thể dùngten_bangđể truy xuất vào table.
Đã xong phần khởi tạo, giờ phần hay ho nhất đây.
2. Insert và update dữ liệu
-
Insert dữ liệu nếu
keyđã có chủ thì ghi đè (đập chậu cuớp bông)iex> :ets.insert(:cache, {"post-1", "world!", %{view: 1}}) true -
Insert dữ liệu, nếu
keyđã có chủ thì bỏ qua.iex> :ets.insert_new(:cache, {"post-1", "Lao!", %{view: 2}}) false iex> :ets.insert_new(:cache, {"post-2", "Vietnam!", %{view: 999}}) true
Dữ liệu cho hàm insert/2 và insert_new/2 là 1 tuple, phần tử đầu tiên của tuple mặc định được dùng làm key.
3. Query dữ liệu
3.1 Query đơn giản: tìm kiếm dữ liệu theo key dùng hàm lookup/2
iex> :ets.lookup(:cache, "post-1")
[{"post-1", "world!", %{view: 1}}]
3.2 Query với nhiều trường dữ liệu với hàm match_object/2
iex> :ets.match_object(:cache, {:"_", "Vietnam!", :"_"})
[{"post-2", "Vietnam!", %{view: 999}}]
- Note
:"_"đánh dấu tại vị trí này sẽ không xài để match dữ liệu, truờng này chứa dữ liệu gì cũng đuợc, anh không quan tâm
3.3 Select trường dữ liệu nào sẽ trả về với match/2
iex> :ets.match_object(:cache, {:"$1", :"$2", :"_"})
[{"post-1", "world!"}, {"post-2", "Vietnam!"}]
- Note
:"$N"dùng đểselectkết quả trả về,Nlà một số nguyên dùng để xác định vị trí của dữ liệu trong kết quả.
iex> :ets.match_object(:cache, {:"$30", :"$2", :"_"})
[{"world!", "post-1"}, {"Vietnam!", "post-2"}]
3.4 Giới hạn kết quả tra về
Sử dụng hàm match/3 hoặc match_object/3 tương tự như match/2 và match_object/2, trong đó tham số thứ 3 là số lượng phần tử sẽ trả về.
# them 1 phan tu
iex> :ets.insert_new(:cache, {"post-3", "Vietnam!", %{view: 1000}})
true
# khong limit
iex> :ets.match_object(:cache, {:"_", "Vietnam!", :"_"})
[{"post-2", "Vietnam!", %{view: 999}}, {"post-3", "Vietnam!", %{view: 1000}}]
# co limit
iex> :ets.match_object(:cache, {:"_", "Vietnam!", :"_"}, 1)
[{"post-2", "Vietnam!", %{view: 999}}]
4. Xoá dữ liệu
Xoá theo key
iex> :ets.delete(:cache, "post-1")
true
Match dữ liệu và xoá. Cách match giống như trong query dữ liệu
iex> :ets.match_delete(:cache, {:"_", "Vietnam!", :"_"})
true
5. Xoá bảng
iex> :ets.delete(:cache)
true
Nếu không xoá thì dữ liệu sẽ tồn tại cho đến khi process kết thúc mới bị mất đi.
6. Các hàm hay xài
member/2kiểm tra xem key đã tồn taị trong bảng hay chưatab2list: đọc tất cả dữ liệu của bảng vào 1 listtab2file: lưu tất cả dữ liệu trên bảng vào 1 file, bạn có thể lưu dữ liệu lại truớc khi process kết thúc và có thể xài lại dữ liệu sau.file2tab: đọc 1 file đuợc lưu bởitab2filevà tạo lại bảng tương ứngto_dest/2: copy toàn bộ dữ liệu từ bảng ETS qua bảng DETS (lưu dữ liệu trên ổ cứng)from_dest/2: copy toàn bộ dữ liệu từ bảng DETS qua bảng ETS
Tham khảo
- http://erlang.org/doc/man/ets.html xem nhiều trò hay
- http://learnyousomeerlang.com/ets
- Ngoài ra Erlang còn hỗ trợ
DETS(disk-based term storage) lưu trên ổ cứng với API tương tự http://erlang.org/doc/man/dets.html