Skip to content

Commit 1c3c7e2

Browse files
committed
add bloom filter
1 parent d87575f commit 1c3c7e2

File tree

2 files changed

+197
-0
lines changed

2 files changed

+197
-0
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
export default class BloomFilter {
2+
/**
3+
* @param {number} size - kích thước của bộ nhớ.
4+
*/
5+
constructor(size = 100) {
6+
// Kích thước bộ lọc Bloom ảnh hưởng trực tiếp đến xác suất dương tính giả.
7+
// Kích thước càng lớn, xác suất càng thấp.
8+
this.size = size;
9+
this.storage = this.createStore(size);
10+
}
11+
12+
/**
13+
* @param {string} item
14+
*/
15+
insert(item) {
16+
const hashValues = this.getHashValues(item);
17+
18+
// Đặt mỗi chỉ mục hashValue thành true.
19+
hashValues.forEach((val) => this.storage.setValue(val));
20+
}
21+
22+
/**
23+
* @param {string} item
24+
* @return {boolean}
25+
*/
26+
mayContain(item) {
27+
const hashValues = this.getHashValues(item);
28+
29+
for (let hashIndex = 0; hashIndex < hashValues.length; hashIndex += 1) {
30+
if (!this.storage.getValue(hashValues[hashIndex])) {
31+
// Chúng ta chắc chắn rằng mục không được chèn.
32+
return false;
33+
}
34+
}
35+
36+
// Mục có thể đã được chèn hoặc không.
37+
return true;
38+
}
39+
40+
/**
41+
* Tạo bộ nhớ dữ liệu cho bộ lọc..
42+
* Chúng ta sử dụng phương pháp này để tạo bộ nhớ nhằm
43+
* tự đóng gói dữ liệu và chỉ cung cấp quyền truy cập
44+
* đến các phương pháp cần thiết.
45+
*
46+
* @param {number} size
47+
* @return {Object}
48+
*/
49+
createStore(size) {
50+
const storage = [];
51+
52+
// Khởi tạo tất cả mục là false
53+
for (let storageCellIndex = 0; storageCellIndex < size; storageCellIndex += 1) {
54+
storage.push(false);
55+
}
56+
57+
const storageInterface = {
58+
getValue(index) {
59+
return storage[index];
60+
},
61+
setValue(index) {
62+
storage[index] = true;
63+
},
64+
};
65+
66+
return storageInterface;
67+
}
68+
69+
/**
70+
* @param {string} item
71+
* @return {number}
72+
*/
73+
hash1(item) {
74+
let hash = 0;
75+
76+
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
77+
const char = item.charCodeAt(charIndex);
78+
hash = (hash << 5) + hash + char;
79+
hash &= hash; // Chuyển sang dạng integer 32bit
80+
hash = Math.abs(hash);
81+
}
82+
83+
return hash % this.size;
84+
}
85+
86+
/**
87+
* @param {string} item
88+
* @return {number}
89+
*/
90+
hash2(item) {
91+
let hash = 5381;
92+
93+
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
94+
const char = item.charCodeAt(charIndex);
95+
hash = (hash << 5) + hash + char; /* hash * 33 + c */
96+
}
97+
98+
return Math.abs(hash % this.size);
99+
}
100+
101+
/**
102+
* @param {string} item
103+
* @return {number}
104+
*/
105+
hash3(item) {
106+
let hash = 0;
107+
108+
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
109+
const char = item.charCodeAt(charIndex);
110+
hash = (hash << 5) - hash;
111+
hash += char;
112+
hash &= hash; // Chuyển sang dạng integer 32bit
113+
}
114+
115+
return Math.abs(hash % this.size);
116+
}
117+
118+
/**
119+
* Chạy tất cả 3 hàm băm trên cùng một đầu vào và trả về mảng kết quả.
120+
* @param {string} item
121+
* @return {number[]}
122+
*/
123+
getHashValues(item) {
124+
return [
125+
this.hash1(item),
126+
this.hash2(item),
127+
this.hash3(item),
128+
];
129+
}
130+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Bộ lọc Bloom
2+
3+
**Bộ lọc Bloom** là một cấu trúc dữ liệu xác suất để kiểm tra xem một phần tử có nằm trong một tập hợp hay không. Nó được thiết kế để có tốc độ cực nhanh và sử dụng bộ nhớ tối thiểu. Có thể có lỗi dương tính giả, nhưng không bao giờ có âm tính giả; nghĩa là kết quả thu được luôn là "nằm trong tập hợp (có thể sai)" hoặc "không nằm trong tập hợp".
4+
5+
Kỹ thuật Bloom dành cho các ứng dụng mà lượng dữ liệu đầu vào sẽ yêu cầu một bộ nhớ cực lớn không có trong thực tế nếu áp dụng các kỹ thuật băm "thông thường".
6+
7+
## Mô tả thuật toán
8+
9+
Bộ lọc Bloom rỗng là một mảng gồm `m` bit, tất cả đều bằng `0`. Giả sử có `k` hàm băm khác nhau, mỗi hàm ánh xạ hoặc băm một số tập hợp phần tử thành một trong các vị trí ở mảng `m`, tạo ra phân phối ngẫu nhiên đồng nhất. Thông thường, `k` là một hằng số, nhỏ hơn nhiều so với` m`, và tỷ lệ thuật với số phần tử được thêm vào.
10+
11+
Một ví dụ của bộ lọc Bloom cho tập hợp `{x, y, z}`. Các mũi tên màu chỉ ra các vị trí mỗi phần tử ánh xạ đến. Phần tử `w` không nằm trong tập hợp `{x, y, z}`, bởi một trong các vị trí nó ánh xạ đến có giá trị 0. Trong ví dụ này, `m = 18``k = 3`.
12+
13+
![Bloom Filter](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)
14+
15+
## Thao tác
16+
17+
Chỉ có hai thao tác có thể thực hiện với bộ lọc bloom là : _chèn__tìm_. Tìm có thể ra dương tính giả. Không thể thực hiện thao tác xoá.
18+
19+
Nói cách khác, bộ lọc có thể nhận thêm mục. Khi kiểm tra xem một mục đã được chèn trước đó chưa, nó có thể cho biết rằng "không" hoặc "có thể".
20+
21+
Cả chèn và tìm đều mất `O (1)`.
22+
23+
## Tạo bộ lọc
24+
25+
Bộ lọc Bloom được tạo ra bằng cách phân bổ một kích thước nhất định. Trong ví dụ, ta sử dụng `100` làm độ dài mặc định. Tất cả các vị trí được khởi tạo là `false`.
26+
27+
### Chèn
28+
29+
Trong quá trình chèn, một số hàm băm, ở đây là hàm băm `3`, được sử dụng để tạo các hàm băm đầu vào. Các hàm băm này xuất ra chỉ mục. Tại mỗi chỉ mục nhận được, ta chỉ cần thay đổi giá trị trong bộ lọc bloom thành `true`.
30+
31+
### Tìm kiếm
32+
33+
Trong quá trình tìm kiếm, các hàm băm giống nhau được gọi và sử dụng để băm đầu vào. Sau đó, ta kiểm tra xem _tất cả_ chỉ mục nhận được có giá trị là `true` bên trong bộ lọc bloom hay không. Nếu _tất cả_ chúng có giá trị là `true`, chúng ta biết rằng bộ lọc bloom có thể đã được chèn giá trị trước đó.
34+
35+
Tuy nhiên, điều đó không chắc chắn, vì có thể các giá trị khác được chèn trước đó đã chuyển giá trị thành `true`. Các giá trị không nhất thiết phải là `true` do mục hiện đang được tìm kiếm. Nên không thể chắc chắn tuyệt đối trừ khi trước đó chỉ có một mục duy nhất đã được chèn vào.
36+
37+
Nhưng khi kiểm tra bộ lọc bloom cho các chỉ mục được trả về bởi các hàm băm, nếu một trong số chúng có giá trị là `false`, chúng ta chắc chắn biết rằng mục đó chưa được chèn trước đó.
38+
39+
## Dương tính giả
40+
41+
Xác suất dương tính giả được xác định bởi ba yếu tố: kích thước của bộ lọc bloom, số lượng hàm băm sử dụng và số lượng mục đã được chèn vào bộ lọc.
42+
43+
Công thức để tính dương tính giả là :
44+
45+
( 1 - e <sup>-kn/m</sup> ) <sup>k</sup>
46+
47+
`k` là số lượng hàm băm
48+
49+
`m` là kích thước bộ lọc
50+
51+
`n` là số lượng mục
52+
53+
Các biến `k`,` m``n`, nên được chọn dựa trên mức độ dương tính giả có thể chấp nhận được. Nếu các giá trị được chọn và xác suất kết quả quá cao, các giá trị phải được điều chỉnh và tính toán lại xác suất.
54+
55+
## Ứng dụng
56+
57+
Bộ lọc Bloom có thể được sử dụng cho các trang web viết blog. Nếu mục đích là chỉ hiển thị cho người đọc những bài báo mà họ chưa từng xem trước đây, thì bộ lọc bloom là hoàn hảo. Nó có thể lưu trữ các giá trị được băm dựa trên các bài báo. Sau khi người dùng đọc một vài bài báo, chúng có thể được chèn vào bộ lọc. Lần sau khi người dùng truy cập trang web, những bài báo đó có thể được lọc ra khỏi kết quả.
58+
59+
Một số bài viết chắc chắn sẽ bị lọc ra do nhầm lẫn, nhưng vẫn có thể chấp nhận được. Sẽ ổn ngay cả khi người dùng không bao giờ xem một bài viết nào đó miễn là họ có những bài khác, hoàn toàn mới để xem mỗi khi họ truy cập trang web.
60+
61+
## Liên kết
62+
63+
- [Wikipedia](https://en.wikipedia.org/wiki/Bloom_filter)
64+
- [Bloom Filters by Example](http://llimllib.github.io/bloomfilter-tutorial/)
65+
- [Calculating False Positive Probability](https://hur.st/bloomfilter/?n=4&p=&m=18&k=3)
66+
- [Bloom Filters on Medium](https://blog.medium.com/what-are-bloom-filters-1ec2a50c68ff)
67+
- [Bloom Filters on YouTube](https://www.youtube.com/watch?v=bEmBh1HtYrw)

0 commit comments

Comments
 (0)