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
value
có thể làset
,ordered_set
,bag
,duplicated_bag
- Kiểu dữ liệu của
value
trê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])
type
là kiểu dữ liệu củavalue
lưu trong bảngset
là 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_set
thằ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.bag
khá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_bag
thằng này ăn tạp giốngbag
nhưng cho phép value trùng nhau
access
giớ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_table
Cá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 đểselect
kết quả trả về,N
là 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/2
kiể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ởitab2file
và 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